zumito-framework 1.2.6 → 1.2.8
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/dist/ZumitoFramework.d.ts +9 -48
- package/dist/ZumitoFramework.js +31 -178
- package/dist/definitions/CommandLoadOptions.d.ts +7 -0
- package/dist/definitions/CommandLoadOptions.js +1 -0
- package/dist/definitions/ErrorType.d.ts +5 -0
- package/dist/definitions/ErrorType.js +6 -0
- package/dist/definitions/FrameworkSettings.d.ts +1 -0
- package/dist/definitions/Module.d.ts +3 -1
- package/dist/definitions/Module.js +7 -3
- package/dist/definitions/parameters/ModuleParameters.d.ts +7 -0
- package/dist/definitions/parameters/ModuleParameters.js +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +11 -1
- package/dist/services/CommandManager.d.ts +4 -1
- package/dist/services/CommandManager.js +21 -3
- package/dist/services/CommandParser.d.ts +16 -0
- package/dist/services/CommandParser.js +39 -0
- package/dist/services/ErrorHandler.d.ts +19 -0
- package/dist/services/ErrorHandler.js +49 -0
- package/dist/services/GuildDataGetter.d.ts +29 -0
- package/dist/services/GuildDataGetter.js +51 -0
- package/dist/services/MemberPermissionChecker.d.ts +19 -0
- package/dist/services/MemberPermissionChecker.js +21 -0
- package/dist/services/ModuleManager.js +1 -1
- package/dist/services/RecursiveObjectMerger.d.ts +3 -0
- package/dist/services/RecursiveObjectMerger.js +20 -0
- package/dist/services/ServiceContainer.js +6 -4
- package/dist/services/SlashCommandRefresher.d.ts +6 -0
- package/dist/services/SlashCommandRefresher.js +73 -0
- package/package.json +1 -1
|
@@ -144,58 +144,19 @@ export declare class ZumitoFramework {
|
|
|
144
144
|
*/
|
|
145
145
|
private initializeDiscordClient;
|
|
146
146
|
/**
|
|
147
|
-
*
|
|
148
|
-
* @param commandLine
|
|
149
|
-
* @returns {string[]}
|
|
150
|
-
* @private
|
|
151
|
-
* @static
|
|
152
|
-
* @example
|
|
153
|
-
* // returns ['a', 'b', 'c']
|
|
154
|
-
* splitCommandLine('a b c');
|
|
155
|
-
* @example
|
|
156
|
-
* // returns ['a', 'b c']
|
|
157
|
-
* splitCommandLine('a "b c"');
|
|
147
|
+
* @deprecated use CommandParser service instead
|
|
158
148
|
*/
|
|
159
149
|
static splitCommandLine(commandLine: any): any;
|
|
160
150
|
/**
|
|
161
|
-
*
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
* @
|
|
166
|
-
* @public
|
|
167
|
-
* @example
|
|
168
|
-
* // returns true if the member has the permission
|
|
169
|
-
* memberHasPermission(member, channel, Permissions.FLAGS.MANAGE_MESSAGES);
|
|
170
|
-
* @example
|
|
171
|
-
* // returns true if the member has the permission
|
|
172
|
-
* memberHasPermission(member, channel, Permissions.FLAGS.MANAGE_MESSAGES | Permissions.FLAGS.MANAGE_CHANNELS);
|
|
173
|
-
* @example
|
|
174
|
-
*/
|
|
175
|
-
memberHasPermission(member: GuildMember, channel: TextChannel, permission: bigint): Promise<boolean>;
|
|
176
|
-
/**
|
|
177
|
-
* Gets the guild settings from the database.
|
|
178
|
-
* If the guild is not in the database, it is added.
|
|
179
|
-
* @param guildId
|
|
180
|
-
* @returns {Promise<any>}
|
|
181
|
-
* @public
|
|
182
|
-
* @async
|
|
183
|
-
* @example
|
|
184
|
-
* // returns the guild settings
|
|
185
|
-
* getGuildSettings('123456789012345678');
|
|
186
|
-
* @example
|
|
187
|
-
* // returns the guild settings
|
|
188
|
-
* getGuildSettings(guild.id);
|
|
189
|
-
* @example
|
|
190
|
-
* // returns the guild settings
|
|
191
|
-
* getGuildSettings(message.guild.id);
|
|
192
|
-
* @example
|
|
193
|
-
* // returns the guild settings
|
|
194
|
-
* getGuildSettings(interaction.guild.id);
|
|
195
|
-
* @example
|
|
196
|
-
* // returns the guild settings
|
|
197
|
-
* getGuildSettings(interaction.guildId);
|
|
151
|
+
* @deprecated use MemberPermissionChecker service
|
|
152
|
+
*/
|
|
153
|
+
memberHasPermission(member: GuildMember, channel: TextChannel, permission: bigint): Promise<any>;
|
|
154
|
+
/**
|
|
155
|
+
* @deprecated use GuildDataGetter service
|
|
198
156
|
*/
|
|
199
157
|
getGuildSettings(guildId: string): Promise<unknown>;
|
|
158
|
+
/**
|
|
159
|
+
* @deprecated
|
|
160
|
+
*/
|
|
200
161
|
refreshSlashCommands(): Promise<void>;
|
|
201
162
|
}
|
package/dist/ZumitoFramework.js
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import * as fs from 'fs';
|
|
2
2
|
import * as url from 'url';
|
|
3
|
-
import { Client,
|
|
3
|
+
import { Client, } from 'discord.js';
|
|
4
4
|
import { ApiResponse } from './definitions/api/ApiResponse.js';
|
|
5
|
-
import { CommandType } from './definitions/commands/CommandType.js';
|
|
6
5
|
import { EventEmitter } from 'events';
|
|
7
|
-
import { REST } from '@discordjs/rest';
|
|
8
|
-
import { Routes } from 'discord-api-types/v9';
|
|
9
6
|
import { StatusManager } from './services/StatusManager.js';
|
|
10
7
|
import { TranslationManager } from './services/TranslationManager.js';
|
|
11
8
|
import { betterLogging } from 'better-logging';
|
|
@@ -19,6 +16,11 @@ import { EventManager } from './services/EventManager.js';
|
|
|
19
16
|
import { CommandManager } from './services/CommandManager.js';
|
|
20
17
|
import { ModuleManager } from './services/ModuleManager.js';
|
|
21
18
|
import { ServiceContainer } from './services/ServiceContainer.js';
|
|
19
|
+
import { GuildDataGetter } from './services/GuildDataGetter.js';
|
|
20
|
+
import { RecursiveObjectMerger } from './services/RecursiveObjectMerger.js';
|
|
21
|
+
import { MemberPermissionChecker } from './services/MemberPermissionChecker.js';
|
|
22
|
+
import { CommandParser } from './services/CommandParser.js';
|
|
23
|
+
import { SlashCommandRefresher } from './services/SlashCommandRefresher.js';
|
|
22
24
|
// import better-logging
|
|
23
25
|
betterLogging(console);
|
|
24
26
|
/**
|
|
@@ -127,6 +129,9 @@ export class ZumitoFramework {
|
|
|
127
129
|
*/
|
|
128
130
|
constructor(settings, callback) {
|
|
129
131
|
this.settings = settings;
|
|
132
|
+
// Register this class instance to service container
|
|
133
|
+
ServiceContainer.addService(ZumitoFramework, [], true, this);
|
|
134
|
+
ServiceContainer.addService(TranslationManager, [], true, this.translations);
|
|
130
135
|
this.modules = new ModuleManager(this);
|
|
131
136
|
this.commands = new CommandManager(this);
|
|
132
137
|
this.events = new Map();
|
|
@@ -136,9 +141,6 @@ export class ZumitoFramework {
|
|
|
136
141
|
if (settings.logLevel) {
|
|
137
142
|
console.logLevel = settings.logLevel;
|
|
138
143
|
}
|
|
139
|
-
// Register this class instance to service container
|
|
140
|
-
ServiceContainer.addService(ZumitoFramework, [], true, this);
|
|
141
|
-
ServiceContainer.addService(TranslationManager, [], true, this.translations);
|
|
142
144
|
this.initialize()
|
|
143
145
|
.then(() => {
|
|
144
146
|
if (callback)
|
|
@@ -238,13 +240,16 @@ export class ZumitoFramework {
|
|
|
238
240
|
else if (fs.existsSync(`${process.cwd()}/src/modules`)) {
|
|
239
241
|
modulesFolder = `${process.cwd()}/src/modules`;
|
|
240
242
|
}
|
|
241
|
-
else
|
|
242
|
-
return;
|
|
243
243
|
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
|
|
244
244
|
await this.registerModule(path.join(__dirname, 'modules', 'core'), 'baseModule');
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
245
|
+
if (modulesFolder) {
|
|
246
|
+
const files = fs.readdirSync(modulesFolder);
|
|
247
|
+
for (const file of files) {
|
|
248
|
+
await this.registerModule(modulesFolder, file);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
else if (this.settings.srcMode == 'monoBundle') {
|
|
252
|
+
await this.registerModule(process.cwd(), 'src');
|
|
248
253
|
}
|
|
249
254
|
// Define models
|
|
250
255
|
const schemas = {};
|
|
@@ -253,7 +258,7 @@ export class ZumitoFramework {
|
|
|
253
258
|
schemas[model.name] = model.getModel(this.database);
|
|
254
259
|
}
|
|
255
260
|
else {
|
|
256
|
-
schemas[model.name] =
|
|
261
|
+
schemas[model.name] = RecursiveObjectMerger.merge(schemas[model.name], model.getModel(this.database));
|
|
257
262
|
}
|
|
258
263
|
});
|
|
259
264
|
Object.keys(schemas).forEach((schemaName) => {
|
|
@@ -292,182 +297,30 @@ export class ZumitoFramework {
|
|
|
292
297
|
});
|
|
293
298
|
}
|
|
294
299
|
/**
|
|
295
|
-
*
|
|
296
|
-
* @param commandLine
|
|
297
|
-
* @returns {string[]}
|
|
298
|
-
* @private
|
|
299
|
-
* @static
|
|
300
|
-
* @example
|
|
301
|
-
* // returns ['a', 'b', 'c']
|
|
302
|
-
* splitCommandLine('a b c');
|
|
303
|
-
* @example
|
|
304
|
-
* // returns ['a', 'b c']
|
|
305
|
-
* splitCommandLine('a "b c"');
|
|
300
|
+
* @deprecated use CommandParser service instead
|
|
306
301
|
*/
|
|
307
302
|
static splitCommandLine(commandLine) {
|
|
308
|
-
|
|
309
|
-
// Find a unique marker for the space character.
|
|
310
|
-
// Start with '<SP>' and repeatedly append '@' if necessary to make it unique.
|
|
311
|
-
let spaceMarker = '<SP>';
|
|
312
|
-
while (commandLine.indexOf(spaceMarker) > -1)
|
|
313
|
-
spaceMarker += '@';
|
|
314
|
-
// Protect double-quoted strings.
|
|
315
|
-
// o Find strings of non-double-quotes, wrapped in double-quotes.
|
|
316
|
-
// o The final double-quote is optional to allow for an unterminated string.
|
|
317
|
-
// o Replace each double-quoted-string with what's inside the qouble-quotes,
|
|
318
|
-
// after each space character has been replaced with the space-marker above.
|
|
319
|
-
// o The outer double-quotes will not be present.
|
|
320
|
-
const noSpacesInQuotes = commandLine.replace(/"([^"]*)"?/g, (fullMatch, capture) => {
|
|
321
|
-
return capture.replace(/ /g, spaceMarker);
|
|
322
|
-
});
|
|
323
|
-
// Now that it is safe to do so, split the command-line at one-or-more spaces.
|
|
324
|
-
const mangledParamArray = noSpacesInQuotes.split(/ +/);
|
|
325
|
-
// Create a new array by restoring spaces from any space-markers.
|
|
326
|
-
const paramArray = mangledParamArray.map((mangledParam) => {
|
|
327
|
-
return mangledParam.replace(RegExp(spaceMarker, 'g'), ' ');
|
|
328
|
-
});
|
|
329
|
-
return paramArray;
|
|
303
|
+
return CommandParser.splitCommandLine(commandLine);
|
|
330
304
|
}
|
|
331
305
|
/**
|
|
332
|
-
*
|
|
333
|
-
* @param member
|
|
334
|
-
* @param channel
|
|
335
|
-
* @param permission
|
|
336
|
-
* @returns {Promise<boolean>}
|
|
337
|
-
* @public
|
|
338
|
-
* @example
|
|
339
|
-
* // returns true if the member has the permission
|
|
340
|
-
* memberHasPermission(member, channel, Permissions.FLAGS.MANAGE_MESSAGES);
|
|
341
|
-
* @example
|
|
342
|
-
* // returns true if the member has the permission
|
|
343
|
-
* memberHasPermission(member, channel, Permissions.FLAGS.MANAGE_MESSAGES | Permissions.FLAGS.MANAGE_CHANNELS);
|
|
344
|
-
* @example
|
|
306
|
+
* @deprecated use MemberPermissionChecker service
|
|
345
307
|
*/
|
|
346
308
|
async memberHasPermission(member, channel, permission) {
|
|
347
|
-
const
|
|
348
|
-
return
|
|
309
|
+
const memberPermissionChecker = ServiceContainer.getService(MemberPermissionChecker);
|
|
310
|
+
return await memberPermissionChecker(member, channel, permission);
|
|
349
311
|
}
|
|
350
312
|
/**
|
|
351
|
-
*
|
|
352
|
-
* If the guild is not in the database, it is added.
|
|
353
|
-
* @param guildId
|
|
354
|
-
* @returns {Promise<any>}
|
|
355
|
-
* @public
|
|
356
|
-
* @async
|
|
357
|
-
* @example
|
|
358
|
-
* // returns the guild settings
|
|
359
|
-
* getGuildSettings('123456789012345678');
|
|
360
|
-
* @example
|
|
361
|
-
* // returns the guild settings
|
|
362
|
-
* getGuildSettings(guild.id);
|
|
363
|
-
* @example
|
|
364
|
-
* // returns the guild settings
|
|
365
|
-
* getGuildSettings(message.guild.id);
|
|
366
|
-
* @example
|
|
367
|
-
* // returns the guild settings
|
|
368
|
-
* getGuildSettings(interaction.guild.id);
|
|
369
|
-
* @example
|
|
370
|
-
* // returns the guild settings
|
|
371
|
-
* getGuildSettings(interaction.guildId);
|
|
313
|
+
* @deprecated use GuildDataGetter service
|
|
372
314
|
*/
|
|
373
315
|
async getGuildSettings(guildId) {
|
|
374
|
-
const
|
|
375
|
-
return await
|
|
376
|
-
Guild.findOne({ where: { guild_id: guildId } }, (err, guild) => {
|
|
377
|
-
if (err)
|
|
378
|
-
reject(err);
|
|
379
|
-
if (guild == null) {
|
|
380
|
-
guild = new Guild({
|
|
381
|
-
guild_id: guildId,
|
|
382
|
-
});
|
|
383
|
-
guild.save((err) => {
|
|
384
|
-
if (err)
|
|
385
|
-
reject(err);
|
|
386
|
-
resolve(guild);
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
resolve(guild);
|
|
391
|
-
}
|
|
392
|
-
});
|
|
393
|
-
});
|
|
316
|
+
const guildDataGetter = ServiceContainer.getService(GuildDataGetter);
|
|
317
|
+
return await guildDataGetter.getGuildSettings(guildId);
|
|
394
318
|
}
|
|
319
|
+
/**
|
|
320
|
+
* @deprecated
|
|
321
|
+
*/
|
|
395
322
|
async refreshSlashCommands() {
|
|
396
|
-
const
|
|
397
|
-
|
|
398
|
-
.filter((command) => command.type == CommandType.slash ||
|
|
399
|
-
command.type == CommandType.separated ||
|
|
400
|
-
command.type == CommandType.any)
|
|
401
|
-
.map((command) => {
|
|
402
|
-
const slashCommand = new SlashCommandBuilder()
|
|
403
|
-
.setName(command.name)
|
|
404
|
-
.setDescription(this.translations.get('command.' + command.name + '.description', 'en'));
|
|
405
|
-
if (command.args) {
|
|
406
|
-
command.args.forEach((arg) => {
|
|
407
|
-
let method;
|
|
408
|
-
switch (arg.type) {
|
|
409
|
-
case 'string':
|
|
410
|
-
method = 'addStringOption';
|
|
411
|
-
break;
|
|
412
|
-
case 'user':
|
|
413
|
-
case 'member':
|
|
414
|
-
method = 'addUserOption';
|
|
415
|
-
break;
|
|
416
|
-
case 'channel':
|
|
417
|
-
method = 'addChannelOption';
|
|
418
|
-
break;
|
|
419
|
-
case 'role':
|
|
420
|
-
method = 'addRoleOption';
|
|
421
|
-
break;
|
|
422
|
-
default:
|
|
423
|
-
throw new Error('Invalid argument type ' + arg.type);
|
|
424
|
-
}
|
|
425
|
-
slashCommand[method]((option) => {
|
|
426
|
-
option.setName(arg.name);
|
|
427
|
-
option.setDescription(this.translations.get('command.' +
|
|
428
|
-
command.name +
|
|
429
|
-
'.args.' +
|
|
430
|
-
arg.name +
|
|
431
|
-
'.description', 'en'));
|
|
432
|
-
option.setRequired(!arg.optional);
|
|
433
|
-
if (arg.choices) {
|
|
434
|
-
// if arg.choices is function, call it
|
|
435
|
-
if (typeof arg.choices == 'function') {
|
|
436
|
-
arg.choices =
|
|
437
|
-
arg.choices();
|
|
438
|
-
}
|
|
439
|
-
arg.choices.forEach((choice) => {
|
|
440
|
-
option.addChoices({
|
|
441
|
-
name: choice.name,
|
|
442
|
-
value: choice.value,
|
|
443
|
-
});
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
return option;
|
|
447
|
-
});
|
|
448
|
-
});
|
|
449
|
-
}
|
|
450
|
-
return slashCommand.toJSON();
|
|
451
|
-
});
|
|
452
|
-
const data = await rest.put(Routes.applicationCommands(this.settings.discordClientOptions.clientId), { body: commands });
|
|
453
|
-
console.debug(`Successfully reloaded ${data.length} of ${commands.length} application (/) commands.`);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
function MergeRecursive(obj1, obj2) {
|
|
457
|
-
for (const p in obj2) {
|
|
458
|
-
try {
|
|
459
|
-
// Property in destination object set; update its value.
|
|
460
|
-
if (obj2[p].constructor == Object) {
|
|
461
|
-
obj1[p] = MergeRecursive(obj1[p], obj2[p]);
|
|
462
|
-
}
|
|
463
|
-
else {
|
|
464
|
-
obj1[p] = obj2[p];
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
catch (e) {
|
|
468
|
-
// Property in destination object not set; create it and set its value.
|
|
469
|
-
obj1[p] = obj2[p];
|
|
470
|
-
}
|
|
323
|
+
const slashCommandRefresher = ServiceContainer.getService(SlashCommandRefresher);
|
|
324
|
+
slashCommandRefresher.refreshSlashCommands();
|
|
471
325
|
}
|
|
472
|
-
return obj1;
|
|
473
326
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -3,14 +3,16 @@ import { Command } from './commands/Command.js';
|
|
|
3
3
|
import { FrameworkEvent } from './FrameworkEvent.js';
|
|
4
4
|
import { DatabaseModel } from './DatabaseModel.js';
|
|
5
5
|
import { CommandManager } from '../services/CommandManager.js';
|
|
6
|
+
import { ModuleParameters } from './parameters/ModuleParameters.js';
|
|
6
7
|
export declare abstract class Module {
|
|
7
8
|
protected path: string;
|
|
9
|
+
protected parameters: ModuleParameters;
|
|
8
10
|
protected framework: ZumitoFramework;
|
|
9
11
|
protected commands: CommandManager;
|
|
10
12
|
protected events: Map<string, FrameworkEvent>;
|
|
11
13
|
protected models: Array<DatabaseModel>;
|
|
12
14
|
protected commandManager: CommandManager;
|
|
13
|
-
constructor(path: any,
|
|
15
|
+
constructor(path: any, parameters?: ModuleParameters);
|
|
14
16
|
initialize(): Promise<void>;
|
|
15
17
|
registerCommands(): Promise<void>;
|
|
16
18
|
getCommands(): Map<string, Command>;
|
|
@@ -1,18 +1,22 @@
|
|
|
1
|
+
import { ZumitoFramework } from '../ZumitoFramework.js';
|
|
1
2
|
import * as fs from 'fs';
|
|
2
3
|
import path from 'path';
|
|
3
4
|
import { ButtonInteraction, CommandInteraction, ModalSubmitInteraction, StringSelectMenuInteraction, } from 'discord.js';
|
|
4
5
|
import { CommandManager } from '../services/CommandManager.js';
|
|
6
|
+
import { ServiceContainer } from '../services/ServiceContainer.js';
|
|
5
7
|
export class Module {
|
|
6
8
|
path;
|
|
9
|
+
parameters;
|
|
7
10
|
framework;
|
|
8
11
|
commands;
|
|
9
12
|
events = new Map();
|
|
10
13
|
models = [];
|
|
11
14
|
commandManager;
|
|
12
|
-
constructor(path,
|
|
15
|
+
constructor(path, parameters) {
|
|
13
16
|
this.path = path;
|
|
14
|
-
this.
|
|
15
|
-
this.
|
|
17
|
+
this.parameters = parameters;
|
|
18
|
+
this.framework = ServiceContainer.getService(ZumitoFramework);
|
|
19
|
+
this.commands = new CommandManager(this.framework);
|
|
16
20
|
}
|
|
17
21
|
async initialize() {
|
|
18
22
|
await this.registerCommands();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -22,4 +22,8 @@ import { ZumitoFramework } from './ZumitoFramework.js';
|
|
|
22
22
|
import * as discord from 'discord.js';
|
|
23
23
|
import { EventParameters } from './definitions/parameters/EventParameters.js';
|
|
24
24
|
import { ServiceContainer } from './services/ServiceContainer.js';
|
|
25
|
-
|
|
25
|
+
import { GuildDataGetter } from './services/GuildDataGetter.js';
|
|
26
|
+
import { CommandParser } from './services/CommandParser.js';
|
|
27
|
+
import { SlashCommandRefresher } from './services/SlashCommandRefresher.js';
|
|
28
|
+
import { ErrorHandler } from './services/ErrorHandler.js';
|
|
29
|
+
export { ZumitoFramework, FrameworkSettings, Command, Module, CommandParameters, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, SelectMenuParameters, CommandType, CommandArgDefinition, CommandChoiceDefinition, ButtonPressed, ButtonPressedParams, TextFormatter, EmojiFallback, DatabaseConfigLoader, DatabaseModel, PresenceDataRule, RuledPresenceData, StatusManagerOptions, discord, EventParameters, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, };
|
package/dist/index.js
CHANGED
|
@@ -14,6 +14,16 @@ import { TranslationManager } from './services/TranslationManager.js';
|
|
|
14
14
|
import { ZumitoFramework } from './ZumitoFramework.js';
|
|
15
15
|
import * as discord from 'discord.js';
|
|
16
16
|
import { ServiceContainer } from './services/ServiceContainer.js';
|
|
17
|
+
import { GuildDataGetter } from './services/GuildDataGetter.js';
|
|
18
|
+
import { MemberPermissionChecker } from './services/MemberPermissionChecker.js';
|
|
19
|
+
import { CommandParser } from './services/CommandParser.js';
|
|
20
|
+
import { SlashCommandRefresher } from './services/SlashCommandRefresher.js';
|
|
21
|
+
import { ErrorHandler } from './services/ErrorHandler.js';
|
|
17
22
|
ServiceContainer.addService(TextFormatter, []);
|
|
18
23
|
ServiceContainer.addService(EmojiFallback, []);
|
|
19
|
-
|
|
24
|
+
ServiceContainer.addService(GuildDataGetter, [ZumitoFramework.name]);
|
|
25
|
+
ServiceContainer.addService(MemberPermissionChecker, []);
|
|
26
|
+
ServiceContainer.addService(CommandParser, []);
|
|
27
|
+
ServiceContainer.addService(SlashCommandRefresher, [ZumitoFramework.name]);
|
|
28
|
+
ServiceContainer.addService(ErrorHandler, ['ZumitoFramework']);
|
|
29
|
+
export { ZumitoFramework, Command, Module, CommandArguments, FrameworkEvent, Translation, TranslationManager, ApiResponse, CommandType, ButtonPressed, TextFormatter, EmojiFallback, DatabaseConfigLoader, DatabaseModel, discord, ServiceContainer, GuildDataGetter, SlashCommandRefresher, CommandParser, ErrorHandler, };
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { ZumitoFramework } from "../ZumitoFramework";
|
|
2
2
|
import { Command } from "../definitions/commands/Command.js";
|
|
3
|
+
import { CommandLoadOptions } from "../definitions/CommandLoadOptions";
|
|
4
|
+
import { ErrorHandler } from "./ErrorHandler";
|
|
3
5
|
export declare class CommandManager {
|
|
4
6
|
protected commands: Map<string, Command>;
|
|
5
7
|
protected framework: ZumitoFramework;
|
|
8
|
+
protected errorHandler: ErrorHandler;
|
|
6
9
|
constructor(framework: any);
|
|
7
10
|
set(name: string, command: Command): void;
|
|
8
11
|
get(name: string): Command;
|
|
@@ -26,7 +29,7 @@ export declare class CommandManager {
|
|
|
26
29
|
* @param folderPath - Absolute path to commands folder
|
|
27
30
|
* @returns {Promise<Map<string, Command>>}
|
|
28
31
|
*/
|
|
29
|
-
loadCommandsFolder(folderPath: string): Promise<Map<string, any>>;
|
|
32
|
+
loadCommandsFolder(folderPath: string, options?: CommandLoadOptions): Promise<Map<string, any>>;
|
|
30
33
|
/**
|
|
31
34
|
* Watch command files on a folder.
|
|
32
35
|
* It loads command when new file is created, update command when file is modified and deletes command when file is deleted.
|
|
@@ -5,11 +5,16 @@ import boxen from "boxen";
|
|
|
5
5
|
import fs from 'fs';
|
|
6
6
|
import { REST, Routes, SlashCommandBuilder } from "discord.js";
|
|
7
7
|
import { CommandType } from "../definitions/commands/CommandType.js";
|
|
8
|
+
import { ErrorHandler } from "./ErrorHandler";
|
|
9
|
+
import { ServiceContainer } from "./ServiceContainer";
|
|
10
|
+
import { ErrorType } from "../definitions/ErrorType";
|
|
8
11
|
export class CommandManager {
|
|
9
12
|
commands;
|
|
10
13
|
framework;
|
|
14
|
+
errorHandler;
|
|
11
15
|
constructor(framework) {
|
|
12
16
|
this.commands = new Map;
|
|
17
|
+
this.errorHandler = ServiceContainer.getService(ErrorHandler);
|
|
13
18
|
this.framework = framework;
|
|
14
19
|
}
|
|
15
20
|
set(name, command) {
|
|
@@ -45,7 +50,15 @@ export class CommandManager {
|
|
|
45
50
|
console.log(e + '\n' + e.name + '\n' + e.stack);
|
|
46
51
|
});
|
|
47
52
|
command = Object.values(command)[0];
|
|
48
|
-
|
|
53
|
+
try {
|
|
54
|
+
command = new command();
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
this.errorHandler.handleError(error, {
|
|
58
|
+
type: ErrorType.CommandInstance,
|
|
59
|
+
command: command,
|
|
60
|
+
});
|
|
61
|
+
}
|
|
49
62
|
this.framework.commands.set(command.constructor.name.toLowerCase(), command);
|
|
50
63
|
console.debug('[🆕🟢 ] Command ' + chalk.blue(filePath.toString().replace(/^.*[\\\/]/, '').split('.').slice(0, -1).join('.')) + ' loaded');
|
|
51
64
|
return command;
|
|
@@ -57,14 +70,19 @@ export class CommandManager {
|
|
|
57
70
|
* @param folderPath - Absolute path to commands folder
|
|
58
71
|
* @returns {Promise<Map<string, Command>>}
|
|
59
72
|
*/
|
|
60
|
-
async loadCommandsFolder(folderPath) {
|
|
73
|
+
async loadCommandsFolder(folderPath, options) {
|
|
61
74
|
const files = fs.readdirSync(folderPath);
|
|
62
75
|
for (const file of files) {
|
|
63
76
|
if (file.endsWith('d.ts'))
|
|
64
77
|
continue;
|
|
65
78
|
if (file.endsWith('.js') || file.endsWith('.ts')) {
|
|
66
79
|
const command = await this.loadCommandFile(path.join(folderPath, file));
|
|
67
|
-
|
|
80
|
+
const commandName = command.constructor.name.toLowerCase();
|
|
81
|
+
if (options?.blacklist && options.blacklist.includes(commandName))
|
|
82
|
+
continue;
|
|
83
|
+
if (options?.whitelist && !options.whitelist.includes(commandName))
|
|
84
|
+
continue;
|
|
85
|
+
this.commands.set(options?.renames?.[commandName] || commandName, command);
|
|
68
86
|
}
|
|
69
87
|
}
|
|
70
88
|
return this.commands;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export declare class CommandParser {
|
|
2
|
+
/**
|
|
3
|
+
* From a command-line string, returns an array of parameters.
|
|
4
|
+
* @param commandLine
|
|
5
|
+
* @returns {string[]}
|
|
6
|
+
* @private
|
|
7
|
+
* @static
|
|
8
|
+
* @example
|
|
9
|
+
* // returns ['a', 'b', 'c']
|
|
10
|
+
* splitCommandLine('a b c');
|
|
11
|
+
* @example
|
|
12
|
+
* // returns ['a', 'b c']
|
|
13
|
+
* splitCommandLine('a "b c"');
|
|
14
|
+
*/
|
|
15
|
+
static splitCommandLine(commandLine: any): any;
|
|
16
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export class CommandParser {
|
|
2
|
+
/**
|
|
3
|
+
* From a command-line string, returns an array of parameters.
|
|
4
|
+
* @param commandLine
|
|
5
|
+
* @returns {string[]}
|
|
6
|
+
* @private
|
|
7
|
+
* @static
|
|
8
|
+
* @example
|
|
9
|
+
* // returns ['a', 'b', 'c']
|
|
10
|
+
* splitCommandLine('a b c');
|
|
11
|
+
* @example
|
|
12
|
+
* // returns ['a', 'b c']
|
|
13
|
+
* splitCommandLine('a "b c"');
|
|
14
|
+
*/
|
|
15
|
+
static splitCommandLine(commandLine) {
|
|
16
|
+
//log( 'commandLine', commandLine ) ;
|
|
17
|
+
// Find a unique marker for the space character.
|
|
18
|
+
// Start with '<SP>' and repeatedly append '@' if necessary to make it unique.
|
|
19
|
+
let spaceMarker = '<SP>';
|
|
20
|
+
while (commandLine.indexOf(spaceMarker) > -1)
|
|
21
|
+
spaceMarker += '@';
|
|
22
|
+
// Protect double-quoted strings.
|
|
23
|
+
// o Find strings of non-double-quotes, wrapped in double-quotes.
|
|
24
|
+
// o The final double-quote is optional to allow for an unterminated string.
|
|
25
|
+
// o Replace each double-quoted-string with what's inside the qouble-quotes,
|
|
26
|
+
// after each space character has been replaced with the space-marker above.
|
|
27
|
+
// o The outer double-quotes will not be present.
|
|
28
|
+
const noSpacesInQuotes = commandLine.replace(/"([^"]*)"?/g, (fullMatch, capture) => {
|
|
29
|
+
return capture.replace(/ /g, spaceMarker);
|
|
30
|
+
});
|
|
31
|
+
// Now that it is safe to do so, split the command-line at one-or-more spaces.
|
|
32
|
+
const mangledParamArray = noSpacesInQuotes.split(/ +/);
|
|
33
|
+
// Create a new array by restoring spaces from any space-markers.
|
|
34
|
+
const paramArray = mangledParamArray.map((mangledParam) => {
|
|
35
|
+
return mangledParam.replace(RegExp(spaceMarker, 'g'), ' ');
|
|
36
|
+
});
|
|
37
|
+
return paramArray;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { ErrorType } from "../definitions/ErrorType";
|
|
2
|
+
import { Command } from "../definitions/commands/Command";
|
|
3
|
+
import { ZumitoFramework } from "../ZumitoFramework";
|
|
4
|
+
declare type BaseErrorOptions = {
|
|
5
|
+
exit?: boolean;
|
|
6
|
+
type: ErrorType;
|
|
7
|
+
};
|
|
8
|
+
declare type CommandErrorOptions = BaseErrorOptions & {
|
|
9
|
+
type: ErrorType.CommandInstance | ErrorType.CommandLoad | ErrorType.CommandRun;
|
|
10
|
+
command: Command;
|
|
11
|
+
};
|
|
12
|
+
export declare class ErrorHandler {
|
|
13
|
+
framework: ZumitoFramework;
|
|
14
|
+
constructor(framework: ZumitoFramework);
|
|
15
|
+
handleError(error: Error, options: BaseErrorOptions | CommandErrorOptions): void;
|
|
16
|
+
handleCommandError(error: Error, options: CommandErrorOptions): void;
|
|
17
|
+
printErrorStack(error: Error): void;
|
|
18
|
+
}
|
|
19
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import ErrorStackParser from "error-stack-parser";
|
|
2
|
+
import { ErrorType } from "../definitions/ErrorType";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
export class ErrorHandler {
|
|
5
|
+
framework;
|
|
6
|
+
constructor(framework) {
|
|
7
|
+
this.framework = framework;
|
|
8
|
+
}
|
|
9
|
+
handleError(error, options) {
|
|
10
|
+
if (options?.type == ErrorType.CommandInstance || options?.type == ErrorType.CommandLoad || options?.type == ErrorType.CommandRun) {
|
|
11
|
+
this.handleCommandError(error, options);
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.error(error.toString());
|
|
15
|
+
}
|
|
16
|
+
this.printErrorStack(error);
|
|
17
|
+
if (options.exit)
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
handleCommandError(error, options) {
|
|
21
|
+
switch (options.type) {
|
|
22
|
+
case ErrorType.CommandInstance:
|
|
23
|
+
console.group(`[❌] Error instanciating command ${options.command.name}`);
|
|
24
|
+
break;
|
|
25
|
+
case ErrorType.CommandLoad:
|
|
26
|
+
console.group(`[❌] Error loading command ${options.command.name}`);
|
|
27
|
+
break;
|
|
28
|
+
case ErrorType.CommandRun:
|
|
29
|
+
console.group(`[❌] Error running command ${options.command.name}`);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
console.line(error.toString());
|
|
33
|
+
console.groupEnd();
|
|
34
|
+
}
|
|
35
|
+
printErrorStack(error) {
|
|
36
|
+
const stackParsedError = ErrorStackParser.parse(error);
|
|
37
|
+
let functionColor = 'blue';
|
|
38
|
+
for (let stack of stackParsedError) {
|
|
39
|
+
const filePath = stack.getFileName();
|
|
40
|
+
let functionName = stack.getFunctionName();
|
|
41
|
+
if (functionName == 'CommandManager.loadCommandFile') {
|
|
42
|
+
functionColor = 'yellow';
|
|
43
|
+
}
|
|
44
|
+
console.line(` at ${chalk.gray(filePath)}:${stack.getLineNumber()}:${stack.getColumnNumber()} ${chalk[functionColor](functionName)}`);
|
|
45
|
+
if (functionName == 'CommandManager.loadCommandFile' && !this.framework.settings.debug)
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { ZumitoFramework } from "../ZumitoFramework";
|
|
2
|
+
export declare class GuildDataGetter {
|
|
3
|
+
framework: ZumitoFramework;
|
|
4
|
+
constructor(framework: ZumitoFramework);
|
|
5
|
+
/**
|
|
6
|
+
* Gets the guild settings from the database.
|
|
7
|
+
* If the guild is not in the database, it is added.
|
|
8
|
+
* @param guildId
|
|
9
|
+
* @returns {Promise<any>}
|
|
10
|
+
* @public
|
|
11
|
+
* @async
|
|
12
|
+
* @example
|
|
13
|
+
* // returns the guild settings
|
|
14
|
+
* getGuildSettings('123456789012345678');
|
|
15
|
+
* @example
|
|
16
|
+
* // returns the guild settings
|
|
17
|
+
* getGuildSettings(guild.id);
|
|
18
|
+
* @example
|
|
19
|
+
* // returns the guild settings
|
|
20
|
+
* getGuildSettings(message.guild.id);
|
|
21
|
+
* @example
|
|
22
|
+
* // returns the guild settings
|
|
23
|
+
* getGuildSettings(interaction.guild.id);
|
|
24
|
+
* @example
|
|
25
|
+
* // returns the guild settings
|
|
26
|
+
* getGuildSettings(interaction.guildId);
|
|
27
|
+
*/
|
|
28
|
+
getGuildSettings(guildId: string): Promise<unknown>;
|
|
29
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export class GuildDataGetter {
|
|
2
|
+
framework;
|
|
3
|
+
constructor(framework) {
|
|
4
|
+
this.framework = framework;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Gets the guild settings from the database.
|
|
8
|
+
* If the guild is not in the database, it is added.
|
|
9
|
+
* @param guildId
|
|
10
|
+
* @returns {Promise<any>}
|
|
11
|
+
* @public
|
|
12
|
+
* @async
|
|
13
|
+
* @example
|
|
14
|
+
* // returns the guild settings
|
|
15
|
+
* getGuildSettings('123456789012345678');
|
|
16
|
+
* @example
|
|
17
|
+
* // returns the guild settings
|
|
18
|
+
* getGuildSettings(guild.id);
|
|
19
|
+
* @example
|
|
20
|
+
* // returns the guild settings
|
|
21
|
+
* getGuildSettings(message.guild.id);
|
|
22
|
+
* @example
|
|
23
|
+
* // returns the guild settings
|
|
24
|
+
* getGuildSettings(interaction.guild.id);
|
|
25
|
+
* @example
|
|
26
|
+
* // returns the guild settings
|
|
27
|
+
* getGuildSettings(interaction.guildId);
|
|
28
|
+
*/
|
|
29
|
+
async getGuildSettings(guildId) {
|
|
30
|
+
const Guild = this.framework.database.models.Guild;
|
|
31
|
+
return await new Promise((resolve, reject) => {
|
|
32
|
+
Guild.findOne({ where: { guild_id: guildId } }, (err, guild) => {
|
|
33
|
+
if (err)
|
|
34
|
+
reject(err);
|
|
35
|
+
if (guild == null) {
|
|
36
|
+
guild = new Guild({
|
|
37
|
+
guild_id: guildId,
|
|
38
|
+
});
|
|
39
|
+
guild.save((err) => {
|
|
40
|
+
if (err)
|
|
41
|
+
reject(err);
|
|
42
|
+
resolve(guild);
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
resolve(guild);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { GuildMember, TextChannel } from "discord.js";
|
|
2
|
+
export declare class MemberPermissionChecker {
|
|
3
|
+
/**
|
|
4
|
+
* Checks if a member has a permission in a channel.
|
|
5
|
+
* @param member
|
|
6
|
+
* @param channel
|
|
7
|
+
* @param permission
|
|
8
|
+
* @returns {Promise<boolean>}
|
|
9
|
+
* @public
|
|
10
|
+
* @example
|
|
11
|
+
* // returns true if the member has the permission
|
|
12
|
+
* memberHasPermission(member, channel, Permissions.FLAGS.MANAGE_MESSAGES);
|
|
13
|
+
* @example
|
|
14
|
+
* // returns true if the member has the permission
|
|
15
|
+
* memberHasPermission(member, channel, Permissions.FLAGS.MANAGE_MESSAGES | Permissions.FLAGS.MANAGE_CHANNELS);
|
|
16
|
+
* @example
|
|
17
|
+
*/
|
|
18
|
+
hasPermissionOnChannel(member: GuildMember, channel: TextChannel, permission: bigint): Promise<boolean>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export class MemberPermissionChecker {
|
|
2
|
+
/**
|
|
3
|
+
* Checks if a member has a permission in a channel.
|
|
4
|
+
* @param member
|
|
5
|
+
* @param channel
|
|
6
|
+
* @param permission
|
|
7
|
+
* @returns {Promise<boolean>}
|
|
8
|
+
* @public
|
|
9
|
+
* @example
|
|
10
|
+
* // returns true if the member has the permission
|
|
11
|
+
* memberHasPermission(member, channel, Permissions.FLAGS.MANAGE_MESSAGES);
|
|
12
|
+
* @example
|
|
13
|
+
* // returns true if the member has the permission
|
|
14
|
+
* memberHasPermission(member, channel, Permissions.FLAGS.MANAGE_MESSAGES | Permissions.FLAGS.MANAGE_CHANNELS);
|
|
15
|
+
* @example
|
|
16
|
+
*/
|
|
17
|
+
async hasPermissionOnChannel(member, channel, permission) {
|
|
18
|
+
const memberPermission = await channel.permissionsFor(member);
|
|
19
|
+
return memberPermission.has(permission);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -61,7 +61,7 @@ export class ModuleManager {
|
|
|
61
61
|
let moduleInstance;
|
|
62
62
|
if (module.constructor) {
|
|
63
63
|
try {
|
|
64
|
-
moduleInstance = new module(rootPath
|
|
64
|
+
moduleInstance = new module(rootPath);
|
|
65
65
|
await moduleInstance.initialize();
|
|
66
66
|
this.modules.set(name || moduleInstance.constructor.name, moduleInstance);
|
|
67
67
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export class RecursiveObjectMerger {
|
|
2
|
+
static merge(obj1, obj2) {
|
|
3
|
+
for (const p in obj2) {
|
|
4
|
+
try {
|
|
5
|
+
// Property in destination object set; update its value.
|
|
6
|
+
if (obj2[p].constructor == Object) {
|
|
7
|
+
obj1[p] = this.merge(obj1[p], obj2[p]);
|
|
8
|
+
}
|
|
9
|
+
else {
|
|
10
|
+
obj1[p] = obj2[p];
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
catch (e) {
|
|
14
|
+
// Property in destination object not set; create it and set its value.
|
|
15
|
+
obj1[p] = obj2[p];
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return obj1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -9,9 +9,10 @@ class ServiceContainerManager {
|
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
11
|
getService(serviceClass) {
|
|
12
|
-
const
|
|
12
|
+
const serviceName = typeof serviceClass == 'string' ? serviceClass : serviceClass.name;
|
|
13
|
+
const service = this.services.get(serviceName);
|
|
13
14
|
if (!service)
|
|
14
|
-
throw new Error(`Service ${
|
|
15
|
+
throw new Error(`Service ${serviceName} not found`);
|
|
15
16
|
if (service.singleton && service.instance)
|
|
16
17
|
return service.instance;
|
|
17
18
|
const dependencies = service.dependencies.map(dependency => this.getService(dependency));
|
|
@@ -21,9 +22,10 @@ class ServiceContainerManager {
|
|
|
21
22
|
return instance;
|
|
22
23
|
}
|
|
23
24
|
addInstance(serviceClass, instance) {
|
|
24
|
-
|
|
25
|
+
const serviceName = typeof serviceClass == 'string' ? serviceClass : serviceClass.name;
|
|
26
|
+
if (!this.services.has(serviceName))
|
|
25
27
|
return;
|
|
26
|
-
this.services.get(
|
|
28
|
+
this.services.get(serviceName).instance = instance;
|
|
27
29
|
}
|
|
28
30
|
}
|
|
29
31
|
export const ServiceContainer = new ServiceContainerManager();
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { REST } from '@discordjs/rest';
|
|
2
|
+
import { Routes } from 'discord-api-types/v9';
|
|
3
|
+
import { CommandType } from "../definitions/commands/CommandType";
|
|
4
|
+
import { SlashCommandBuilder } from "discord.js";
|
|
5
|
+
export class SlashCommandRefresher {
|
|
6
|
+
framework;
|
|
7
|
+
constructor(framework) {
|
|
8
|
+
this.framework = framework;
|
|
9
|
+
}
|
|
10
|
+
/*
|
|
11
|
+
* Update slash commands on discord
|
|
12
|
+
*/
|
|
13
|
+
async refreshSlashCommands() {
|
|
14
|
+
const rest = new REST({ version: '10' }).setToken(this.framework.settings.discordClientOptions.token);
|
|
15
|
+
const commands = Array.from(this.framework.commands.getAll().values())
|
|
16
|
+
.filter((command) => command.type == CommandType.slash ||
|
|
17
|
+
command.type == CommandType.separated ||
|
|
18
|
+
command.type == CommandType.any)
|
|
19
|
+
.map((command) => {
|
|
20
|
+
const slashCommand = new SlashCommandBuilder()
|
|
21
|
+
.setName(command.name)
|
|
22
|
+
.setDescription(this.framework.translations.get('command.' + command.name + '.description', 'en'));
|
|
23
|
+
if (command.args) {
|
|
24
|
+
command.args.forEach((arg) => {
|
|
25
|
+
let method;
|
|
26
|
+
switch (arg.type) {
|
|
27
|
+
case 'string':
|
|
28
|
+
method = 'addStringOption';
|
|
29
|
+
break;
|
|
30
|
+
case 'user':
|
|
31
|
+
case 'member':
|
|
32
|
+
method = 'addUserOption';
|
|
33
|
+
break;
|
|
34
|
+
case 'channel':
|
|
35
|
+
method = 'addChannelOption';
|
|
36
|
+
break;
|
|
37
|
+
case 'role':
|
|
38
|
+
method = 'addRoleOption';
|
|
39
|
+
break;
|
|
40
|
+
default:
|
|
41
|
+
throw new Error('Invalid argument type ' + arg.type);
|
|
42
|
+
}
|
|
43
|
+
slashCommand[method]((option) => {
|
|
44
|
+
option.setName(arg.name);
|
|
45
|
+
option.setDescription(this.framework.translations.get('command.' +
|
|
46
|
+
command.name +
|
|
47
|
+
'.args.' +
|
|
48
|
+
arg.name +
|
|
49
|
+
'.description', 'en'));
|
|
50
|
+
option.setRequired(!arg.optional);
|
|
51
|
+
if (arg.choices) {
|
|
52
|
+
// if arg.choices is function, call it
|
|
53
|
+
if (typeof arg.choices == 'function') {
|
|
54
|
+
arg.choices =
|
|
55
|
+
arg.choices();
|
|
56
|
+
}
|
|
57
|
+
arg.choices.forEach((choice) => {
|
|
58
|
+
option.addChoices({
|
|
59
|
+
name: choice.name,
|
|
60
|
+
value: choice.value,
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return option;
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
return slashCommand.toJSON();
|
|
69
|
+
});
|
|
70
|
+
const data = await rest.put(Routes.applicationCommands(this.framework.settings.discordClientOptions.clientId), { body: commands });
|
|
71
|
+
console.debug(`Successfully reloaded ${data.length} of ${commands.length} application (/) commands.`);
|
|
72
|
+
}
|
|
73
|
+
}
|