zumito-framework 1.2.16 → 1.2.18

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.
Files changed (37) hide show
  1. package/README.md +4 -0
  2. package/dist/ZumitoFramework.d.ts +1 -1
  3. package/dist/ZumitoFramework.js +3 -1
  4. package/dist/definitions/ErrorType.d.ts +2 -1
  5. package/dist/definitions/ErrorType.js +1 -0
  6. package/dist/definitions/FrameworkSettings.d.ts +4 -19
  7. package/dist/definitions/commands/Command.d.ts +8 -12
  8. package/dist/definitions/commands/Command.js +9 -4
  9. package/dist/definitions/commands/CommandBinds.d.ts +4 -0
  10. package/dist/definitions/commands/CommandBinds.js +1 -0
  11. package/dist/definitions/commands/CommandParameters.d.ts +10 -3
  12. package/dist/definitions/parameters/EventParameters.d.ts +6 -0
  13. package/dist/definitions/parameters/SelectMenuParameters.d.ts +6 -0
  14. package/dist/definitions/settings/FrameworkSettings.d.ts +24 -0
  15. package/dist/definitions/settings/FrameworkSettings.js +1 -0
  16. package/dist/definitions/settings/InteractionHandlerSettings.d.ts +3 -0
  17. package/dist/definitions/settings/InteractionHandlerSettings.js +1 -0
  18. package/dist/index.d.ts +4 -1
  19. package/dist/index.js +5 -1
  20. package/dist/modules/core/baseModule/events/discord/InteractionCreate.d.ts +4 -3
  21. package/dist/modules/core/baseModule/events/discord/InteractionCreate.js +8 -122
  22. package/dist/modules/core/baseModule/events/discord/MessageCreate.d.ts +7 -0
  23. package/dist/modules/core/baseModule/events/discord/MessageCreate.js +35 -36
  24. package/dist/services/CommandManager.js +16 -9
  25. package/dist/services/CommandParser.d.ts +7 -0
  26. package/dist/services/CommandParser.js +32 -0
  27. package/dist/services/ErrorHandler.d.ts +2 -1
  28. package/dist/services/ErrorHandler.js +69 -7
  29. package/dist/services/InteractionHandler.d.ts +21 -0
  30. package/dist/services/InteractionHandler.js +206 -0
  31. package/dist/services/ServiceContainer.d.ts +9 -1
  32. package/dist/services/ServiceContainer.js +14 -2
  33. package/dist/services/SlashCommandRefresher.d.ts +4 -1
  34. package/dist/services/SlashCommandRefresher.js +67 -50
  35. package/dist/services/TranslationManager.d.ts +1 -0
  36. package/dist/services/TranslationManager.js +12 -0
  37. package/package.json +6 -1
@@ -36,4 +36,36 @@ export class CommandParser {
36
36
  });
37
37
  return paramArray;
38
38
  }
39
+ static async parseFromSplitedString(args, argDefinitions, guild) {
40
+ const parsedArgs = new Map();
41
+ const errors = [];
42
+ for (let i = 0; i < args.length; i++) {
43
+ const arg = args[i];
44
+ const type = argDefinitions[i]?.type;
45
+ if (type) {
46
+ if (type == 'member' || type == 'user') {
47
+ const member = await guild.members.cache.get(arg.replace(/[<@!>]/g, ''));
48
+ if (member) {
49
+ if (type == 'user') {
50
+ parsedArgs.set(argDefinitions[i].name, member.user);
51
+ }
52
+ else {
53
+ parsedArgs.set(argDefinitions[i].name, member);
54
+ }
55
+ }
56
+ else {
57
+ errors.push('Invalid user.');
58
+ }
59
+ }
60
+ else if (type == 'string') {
61
+ parsedArgs.set(argDefinitions[i]?.name || i.toString(), arg);
62
+ }
63
+ }
64
+ }
65
+ return {
66
+ validated: errors.length == 0,
67
+ errors,
68
+ parsedArgs,
69
+ };
70
+ }
39
71
  }
@@ -12,8 +12,9 @@ declare type CommandErrorOptions = BaseErrorOptions & {
12
12
  export declare class ErrorHandler {
13
13
  framework: ZumitoFramework;
14
14
  constructor(framework: ZumitoFramework);
15
- handleError(error: Error, options: BaseErrorOptions | CommandErrorOptions): void;
15
+ handleError(error: any, options: BaseErrorOptions | CommandErrorOptions): void;
16
16
  handleCommandError(error: Error, options: CommandErrorOptions): void;
17
+ handleShapeShiftErrors(error: any): void;
17
18
  printErrorStack(error: Error): void;
18
19
  }
19
20
  export {};
@@ -1,6 +1,7 @@
1
1
  import ErrorStackParser from "error-stack-parser";
2
2
  import { ErrorType } from "../definitions/ErrorType";
3
3
  import chalk from "chalk";
4
+ import sf from 'source-fragment';
4
5
  export class ErrorHandler {
5
6
  framework;
6
7
  constructor(framework) {
@@ -10,8 +11,20 @@ export class ErrorHandler {
10
11
  if (options?.type == ErrorType.CommandInstance || options?.type == ErrorType.CommandLoad || options?.type == ErrorType.CommandRun) {
11
12
  this.handleCommandError(error, options);
12
13
  }
14
+ else if (error.constructor.name == 'CombinedError') {
15
+ this.handleShapeShiftErrors(error);
16
+ }
17
+ else if (error.constructor?.name == "ExpectedValidationError") {
18
+ console.error(`Validation error: Expected ${error.expected}, but received ${error.given}.`);
19
+ console.line('');
20
+ }
21
+ else if (error.constructor.name == "ValidationError") {
22
+ console.error(`Validation error: ${error.validator} received invalid input: ${error.given}`);
23
+ console.line('');
24
+ }
13
25
  else {
14
26
  console.error(error.toString());
27
+ console.line('');
15
28
  }
16
29
  this.printErrorStack(error);
17
30
  if (options.exit)
@@ -20,7 +33,7 @@ export class ErrorHandler {
20
33
  handleCommandError(error, options) {
21
34
  switch (options.type) {
22
35
  case ErrorType.CommandInstance:
23
- console.group(`[❌] Error instanciating command ${options.command.name}`);
36
+ console.group(`[❌] Error instanciating command ${options?.command?.name}`);
24
37
  break;
25
38
  case ErrorType.CommandLoad:
26
39
  console.group(`[❌] Error loading command ${options.command.name}`);
@@ -29,21 +42,70 @@ export class ErrorHandler {
29
42
  console.group(`[❌] Error running command ${options.command.name}`);
30
43
  break;
31
44
  }
32
- console.line(error.toString());
33
- console.groupEnd();
45
+ if (error.constructor.name == 'CombinedError') {
46
+ console.groupEnd();
47
+ this.handleShapeShiftErrors(error);
48
+ }
49
+ else {
50
+ console.line(chalk.red('Error:'));
51
+ console.line(error.toString());
52
+ console.line('');
53
+ console.groupEnd();
54
+ }
55
+ }
56
+ handleShapeShiftErrors(error) {
57
+ if (error.constructor.name == 'CombinedError') {
58
+ error.errors.forEach(err => {
59
+ this.handleError(err, {
60
+ type: ErrorType.Other
61
+ });
62
+ });
63
+ }
34
64
  }
35
65
  printErrorStack(error) {
36
66
  const stackParsedError = ErrorStackParser.parse(error);
37
67
  let functionColor = 'blue';
38
- for (let stack of stackParsedError) {
39
- const filePath = stack.getFileName();
40
- let functionName = stack.getFunctionName();
68
+ const lines = [];
69
+ let codeFragment;
70
+ let lastStack;
71
+ for (const stack of stackParsedError) {
72
+ const filePath = stack.getFileName().replace(process.cwd(), '.').replace('file://', '');
73
+ const functionName = stack.getFunctionName();
41
74
  if (functionName == 'CommandManager.loadCommandFile') {
42
75
  functionColor = 'yellow';
43
76
  }
44
- console.line(` at ${chalk.gray(filePath)}:${stack.getLineNumber()}:${stack.getColumnNumber()} ${chalk[functionColor](functionName)}`);
77
+ lines.push(` at ${chalk.gray(filePath)}:${stack.getLineNumber()}:${stack.getColumnNumber()} ${chalk[functionColor](functionName)}`);
45
78
  if (functionName == 'CommandManager.loadCommandFile' && !this.framework.settings.debug)
46
79
  break;
80
+ if (!codeFragment && functionName.includes('.execute')) {
81
+ let columnEnd = -1;
82
+ if (lastStack) {
83
+ if (lastStack.getFunctionName().contains('.')) {
84
+ columnEnd = lastStack.getFunctionName().split('.').at(-1).length;
85
+ }
86
+ else {
87
+ columnEnd = lastStack.getFunctionName().length;
88
+ }
89
+ }
90
+ codeFragment = {
91
+ path: `${filePath}:${stack.getLineNumber()}:${stack.getColumnNumber()}`,
92
+ code: sf(`${filePath}:${stack.getLineNumber()}:${stack.getColumnNumber()}:${stack.getLineNumber()}:${stack.getColumnNumber() + columnEnd}`, {
93
+ format: 'tty',
94
+ linesBefore: 2,
95
+ linesAfter: 2,
96
+ })
97
+ };
98
+ }
99
+ lastStack = stack;
100
+ }
101
+ // Log code fragment
102
+ if (codeFragment) {
103
+ console.line(chalk.blue('File: ') + `${codeFragment.path}`);
104
+ console.line(codeFragment.code);
105
+ console.line('');
47
106
  }
107
+ // Log stack
108
+ console.line(chalk.blue('StackTrace:'));
109
+ lines.forEach(line => console.line(line));
48
110
  }
49
111
  }
@@ -0,0 +1,21 @@
1
+ import { ButtonInteraction, Client, CommandInteraction, Interaction, ModalSubmitInteraction, StringSelectMenuInteraction } from "discord.js";
2
+ import { CommandManager } from "./CommandManager";
3
+ import { GuildDataGetter } from "./GuildDataGetter";
4
+ import { TranslationManager } from "./TranslationManager";
5
+ import { EventManager } from "./EventManager";
6
+ import { InteractionHandlerSettings } from "@definitions/settings/InteractionHandlerSettings";
7
+ import { ErrorHandler } from "./ErrorHandler";
8
+ export declare class InteractionHandler {
9
+ protected commandManager: CommandManager;
10
+ protected guildDataGetter: GuildDataGetter;
11
+ protected client: Client;
12
+ protected translationManager: TranslationManager;
13
+ protected eventManager: EventManager;
14
+ protected errorHandler: ErrorHandler;
15
+ constructor();
16
+ handleInteraction(interaction: Interaction, params?: InteractionHandlerSettings): Promise<void>;
17
+ handleCommandInteraction(interaction: CommandInteraction, guildSettings?: any): Promise<void>;
18
+ handleButtonInteraction(interaction: ButtonInteraction, guildSettings?: any): Promise<void>;
19
+ handleSelectMenu(interaction: StringSelectMenuInteraction, guildSettings?: any): Promise<void>;
20
+ handleModalInteraction(interaction: ModalSubmitInteraction, guildSettings?: any): Promise<void>;
21
+ }
@@ -0,0 +1,206 @@
1
+ import { Client } from "discord.js";
2
+ import { CommandManager } from "./CommandManager";
3
+ import { GuildDataGetter } from "./GuildDataGetter";
4
+ import { ServiceContainer } from "./ServiceContainer";
5
+ import { CommandType } from "../definitions/commands/CommandType";
6
+ import { ZumitoFramework } from "../ZumitoFramework";
7
+ import { TranslationManager } from "./TranslationManager";
8
+ import { EventManager } from "./EventManager";
9
+ import { ErrorHandler } from "./ErrorHandler";
10
+ import { ErrorType } from "../definitions/ErrorType";
11
+ export class InteractionHandler {
12
+ commandManager;
13
+ guildDataGetter;
14
+ client;
15
+ translationManager;
16
+ eventManager;
17
+ errorHandler;
18
+ constructor() {
19
+ this.commandManager = ServiceContainer.getService(CommandManager);
20
+ this.guildDataGetter = ServiceContainer.getService(GuildDataGetter);
21
+ this.client = ServiceContainer.getService(Client);
22
+ this.translationManager = ServiceContainer.getService(TranslationManager);
23
+ this.eventManager = ServiceContainer.getService(EventManager);
24
+ this.errorHandler = ServiceContainer.getService(ErrorHandler);
25
+ }
26
+ async handleInteraction(interaction, params) {
27
+ if (interaction.isCommand()) {
28
+ if (params?.disabledHandlers?.includes("command"))
29
+ return;
30
+ await this.handleCommandInteraction(interaction);
31
+ }
32
+ else if (interaction.isButton()) {
33
+ if (params?.disabledHandlers?.includes("button"))
34
+ return;
35
+ await this.handleButtonInteraction(interaction);
36
+ }
37
+ else if (interaction.isStringSelectMenu()) {
38
+ if (params?.disabledHandlers?.includes("selectMenu"))
39
+ return;
40
+ await this.handleSelectMenu(interaction);
41
+ }
42
+ else if (interaction.isModalSubmit()) {
43
+ if (params?.disabledHandlers?.includes("modal"))
44
+ return;
45
+ await this.handleModalInteraction(interaction);
46
+ }
47
+ }
48
+ async handleCommandInteraction(interaction, guildSettings) {
49
+ const subcommandName = interaction.options.getSubcommand(false);
50
+ const commandName = interaction.commandName;
51
+ let commandInstance;
52
+ if (subcommandName) {
53
+ commandInstance = Array.from(this.commandManager.getAll().values()).find(c => c.name == subcommandName && c.parent == commandName);
54
+ }
55
+ else {
56
+ commandInstance = this.commandManager.get(commandName);
57
+ }
58
+ if (!commandInstance)
59
+ return;
60
+ const framework = ServiceContainer.getService(ZumitoFramework);
61
+ const args = new Map();
62
+ commandInstance.args.forEach((arg) => {
63
+ const option = (interaction).options.get(arg.name);
64
+ if (option) {
65
+ switch (arg.type) {
66
+ case 'user':
67
+ args.set(arg.name, option.user);
68
+ break;
69
+ case 'member':
70
+ args.set(arg.name, option.member);
71
+ break;
72
+ default:
73
+ args.set(arg.name, option.value ||
74
+ option.user ||
75
+ option.role ||
76
+ option.channel ||
77
+ option.options ||
78
+ option.message ||
79
+ option.member ||
80
+ option.focused ||
81
+ option.autocomplete ||
82
+ option.attachment);
83
+ break;
84
+ }
85
+ }
86
+ });
87
+ if (![CommandType.any, CommandType.separated, CommandType.slash,].includes(commandInstance.type))
88
+ return;
89
+ if (!guildSettings && interaction.guildId) {
90
+ guildSettings = await ServiceContainer.getService(GuildDataGetter).getGuildSettings(interaction.guildId);
91
+ }
92
+ const trans = this.translationManager.getShortHandMethod('command.' + commandInstance.name, guildSettings?.lang);
93
+ if (commandInstance.type === CommandType.separated ||
94
+ commandInstance.type === CommandType.slash) {
95
+ await commandInstance.executeSlashCommand({
96
+ client: this.client,
97
+ interaction, args, framework, guildSettings, trans,
98
+ });
99
+ }
100
+ else {
101
+ try {
102
+ await commandInstance.execute({
103
+ client: this.client,
104
+ interaction, args, framework, guildSettings, trans,
105
+ }).catch((error) => {
106
+ this.errorHandler.handleError(error, {
107
+ command: commandInstance,
108
+ type: ErrorType.CommandRun,
109
+ });
110
+ interaction.reply({
111
+ content: "An error ocurred while running this command.",
112
+ ephemeral: true
113
+ });
114
+ });
115
+ }
116
+ catch (error) {
117
+ this.errorHandler.handleError(error, {
118
+ command: commandInstance,
119
+ type: ErrorType.CommandRun,
120
+ });
121
+ interaction.reply({
122
+ content: "An error ocurred while running this command.",
123
+ ephemeral: true,
124
+ });
125
+ }
126
+ }
127
+ }
128
+ async handleButtonInteraction(interaction, guildSettings) {
129
+ const framework = ServiceContainer.getService(ZumitoFramework);
130
+ const path = interaction.customId.split('.');
131
+ const commandInstance = this.commandManager.get(path[0]);
132
+ if (!commandInstance)
133
+ throw new Error(`Command ${path[0]} not found or button id bad formatted`);
134
+ if (!guildSettings && interaction.guildId) {
135
+ guildSettings = await ServiceContainer.getService(GuildDataGetter).getGuildSettings(interaction.guildId);
136
+ }
137
+ // If the command has impements ButtonPress class then execute the method
138
+ if (commandInstance.constructor.prototype.hasOwnProperty('buttonPressed')) {
139
+ commandInstance.buttonPressed({
140
+ client: this.client,
141
+ path,
142
+ interaction,
143
+ framework,
144
+ guildSettings,
145
+ });
146
+ }
147
+ }
148
+ async handleSelectMenu(interaction, guildSettings) {
149
+ const path = interaction.customId.split('.');
150
+ const commandInstance = this.commandManager.get(path[0]);
151
+ if (!commandInstance)
152
+ throw new Error(`Command ${path[0]} not found or select menu id bad formatted`);
153
+ if (!guildSettings && interaction.guildId) {
154
+ guildSettings = await ServiceContainer.getService(GuildDataGetter).getGuildSettings(interaction.guildId);
155
+ }
156
+ const trans = this.translationManager.getShortHandMethod('command.' + commandInstance.name, guildSettings?.lang);
157
+ const framework = ServiceContainer.getService(ZumitoFramework);
158
+ if (commandInstance.binds?.selectMenu) {
159
+ commandInstance.binds?.selectMenu({
160
+ path,
161
+ interaction,
162
+ client: this.client,
163
+ framework,
164
+ guildSettings,
165
+ trans,
166
+ });
167
+ }
168
+ else if ( // Deprecated
169
+ commandInstance.constructor.prototype.hasOwnProperty('selectMenu')) {
170
+ commandInstance.selectMenu({
171
+ path,
172
+ interaction,
173
+ client: this.client,
174
+ framework,
175
+ guildSettings,
176
+ trans,
177
+ });
178
+ }
179
+ }
180
+ async handleModalInteraction(interaction, guildSettings) {
181
+ const path = interaction.customId.split('.');
182
+ const commandInstance = this.commandManager.get(path[0]);
183
+ if (!commandInstance) {
184
+ throw new Error(`Command ${path[0]} not found or modal id bad formatted`);
185
+ }
186
+ const framework = ServiceContainer.getService(ZumitoFramework);
187
+ if (commandInstance.modalSubmit) {
188
+ if (!guildSettings && interaction.guildId) {
189
+ guildSettings = await ServiceContainer.getService(GuildDataGetter).getGuildSettings(interaction.guildId);
190
+ }
191
+ commandInstance.modalSubmit({
192
+ client: this.client,
193
+ path,
194
+ interaction,
195
+ framework,
196
+ guildSettings,
197
+ });
198
+ }
199
+ else {
200
+ this.eventManager.emitEvent('modalSubmit', 'framework', {
201
+ client: this.client,
202
+ path, interaction, framework, guildSettings,
203
+ });
204
+ }
205
+ }
206
+ }
@@ -1 +1,9 @@
1
- export declare const ServiceContainer: any;
1
+ declare class ServiceContainerManager {
2
+ private services;
3
+ addService(serviceClass: any, dependencies: string[], singleton?: boolean, instance?: any): void;
4
+ getService<T>(serviceClass: new (...args: any[]) => T | string): T;
5
+ getServiceByName<T>(serviceName: string): T;
6
+ addInstance(serviceClass: any, instance: any): void;
7
+ }
8
+ export declare const ServiceContainer: ServiceContainerManager;
9
+ export {};
@@ -9,13 +9,25 @@ class ServiceContainerManager {
9
9
  });
10
10
  }
11
11
  getService(serviceClass) {
12
- const serviceName = typeof serviceClass == 'string' ? serviceClass : serviceClass.name;
12
+ const serviceName = typeof serviceClass === 'string' ? serviceClass : serviceClass.name;
13
+ const service = this.services.get(serviceName);
14
+ if (!service)
15
+ throw new Error(`Service ${serviceName} not found`);
16
+ if (service.singleton && service.instance)
17
+ return service.instance;
18
+ const dependencies = service.dependencies.map(dependency => this.getServiceByName(dependency));
19
+ const instance = new service.class(...dependencies);
20
+ if (service.singleton)
21
+ service.instance = instance;
22
+ return instance;
23
+ }
24
+ getServiceByName(serviceName) {
13
25
  const service = this.services.get(serviceName);
14
26
  if (!service)
15
27
  throw new Error(`Service ${serviceName} not found`);
16
28
  if (service.singleton && service.instance)
17
29
  return service.instance;
18
- const dependencies = service.dependencies.map(dependency => this.getService(dependency));
30
+ const dependencies = service.dependencies.map(dependency => this.getServiceByName(dependency));
19
31
  const instance = new service.class(...dependencies);
20
32
  if (service.singleton)
21
33
  service.instance = instance;
@@ -1,6 +1,9 @@
1
1
  import { ZumitoFramework } from "../ZumitoFramework";
2
+ import { Command } from "../definitions/commands/Command";
3
+ import { SlashCommandSubcommandBuilder } from "discord.js";
2
4
  export declare class SlashCommandRefresher {
3
- framework: ZumitoFramework;
5
+ protected framework: ZumitoFramework;
4
6
  constructor(framework: ZumitoFramework);
5
7
  refreshSlashCommands(): Promise<void>;
8
+ mapCommand(command: Command, commandBuilder?: SlashCommandSubcommandBuilder): import("discord.js").RESTPostAPIChatInputApplicationCommandsJSONBody | import("discord.js").APIApplicationCommandSubcommandOption;
6
9
  }
@@ -13,61 +13,78 @@ export class SlashCommandRefresher {
13
13
  async refreshSlashCommands() {
14
14
  const rest = new REST({ version: '10' }).setToken(this.framework.settings.discordClientOptions.token);
15
15
  const commands = Array.from(this.framework.commands.getAll().values())
16
- .filter((command) => command.type == CommandType.slash ||
16
+ .filter((command) => (command.type == CommandType.slash ||
17
17
  command.type == CommandType.separated ||
18
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
- });
19
+ && !command.parent)
20
+ .map(command => this.mapCommand(command));
21
+ const data = await rest.put(Routes.applicationCommands(this.framework.settings.discordClientOptions.clientId), { body: commands });
22
+ console.debug(`Successfully reloaded ${data.length} of ${commands.length} application (/) commands.`);
23
+ }
24
+ mapCommand(command, commandBuilder) {
25
+ const slashCommand = commandBuilder || new SlashCommandBuilder();
26
+ slashCommand
27
+ .setName(command.name)
28
+ .setDescription(this.framework.translations.get('command.' + command.name + '.description', 'en'));
29
+ if (command.args) {
30
+ command.args.forEach((arg) => {
31
+ let method;
32
+ switch (arg.type) {
33
+ case 'string':
34
+ method = 'addStringOption';
35
+ break;
36
+ case 'user':
37
+ case 'member':
38
+ method = 'addUserOption';
39
+ break;
40
+ case 'channel':
41
+ method = 'addChannelOption';
42
+ break;
43
+ case 'role':
44
+ method = 'addRoleOption';
45
+ break;
46
+ default:
47
+ throw new Error('Invalid argument type ' + arg.type);
48
+ }
49
+ slashCommand[method]((option) => {
50
+ option.setName(arg.name);
51
+ option.setDescription(this.framework.translations.get('command.' +
52
+ command.name +
53
+ '.args.' +
54
+ arg.name +
55
+ '.description', 'en'));
56
+ option.setRequired(!arg.optional);
57
+ if (arg.choices) {
58
+ // if arg.choices is function, call it
59
+ if (typeof arg.choices == 'function') {
60
+ arg.choices =
61
+ arg.choices();
63
62
  }
64
- return option;
65
- });
63
+ arg.choices.forEach((choice) => {
64
+ option.addChoices({
65
+ name: choice.name,
66
+ value: choice.value,
67
+ });
68
+ });
69
+ }
70
+ return option;
71
+ });
72
+ });
73
+ }
74
+ Array.from(this.framework.commands.getAll().values())
75
+ .filter((subcommand) => (subcommand.type == CommandType.slash ||
76
+ subcommand.type == CommandType.separated ||
77
+ subcommand.type == CommandType.any)
78
+ && subcommand.parent
79
+ && subcommand.parent == command.name)
80
+ .forEach(subcommand => {
81
+ if (!commandBuilder) {
82
+ slashCommand.addSubcommand((subcommandSlashBuilder) => {
83
+ this.mapCommand(subcommand, subcommandSlashBuilder);
84
+ return subcommandSlashBuilder;
66
85
  });
67
86
  }
68
- return slashCommand.toJSON();
69
87
  });
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.`);
88
+ return slashCommand.toJSON();
72
89
  }
73
90
  }
@@ -31,4 +31,5 @@ export declare class TranslationManager {
31
31
  */
32
32
  registerTranslationsFromFolder(folderPath: string, baseKey?: string, watch?: boolean): Promise<void>;
33
33
  watchTranslationFolder(folderPath: string, baseKey: string): void;
34
+ getShortHandMethod(keyPrefix: string, language?: string): (key: string, params?: any, lang?: string) => string;
34
35
  }
@@ -119,4 +119,16 @@ export class TranslationManager {
119
119
  // TODO: Handle file removal
120
120
  //.on('unlink', function(path) {console.log('File', path, 'has been removed');})
121
121
  }
122
+ getShortHandMethod(keyPrefix, language) {
123
+ return (key, params, lang) => {
124
+ if (key.startsWith('$')) {
125
+ return this.get(key.replace('$', ''), lang || language, params);
126
+ }
127
+ else {
128
+ if (!keyPrefix.endsWith('.'))
129
+ keyPrefix += '.';
130
+ return this.get(keyPrefix + key, lang || language, params);
131
+ }
132
+ };
133
+ }
122
134
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zumito-framework",
3
- "version": "1.2.16",
3
+ "version": "1.2.18",
4
4
  "description": "Discord.js bot framework",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,6 +33,7 @@
33
33
  "express": "^4.18.1",
34
34
  "leven": "^4.0.0",
35
35
  "mongoose": "^6.6.5",
36
+ "source-fragment": "^1.1.0",
36
37
  "tingodb": "^0.6.1",
37
38
  "tseep": "^1.2.2",
38
39
  "zumito-db": "^1.0.0"
@@ -54,6 +55,10 @@
54
55
  ".": "./dist/index.js",
55
56
  "./discord": "./dist/discord/index.js"
56
57
  },
58
+ "_moduleAliases": {
59
+ "@definitions": "definitions",
60
+ "@services": "services"
61
+ },
57
62
  "typesVersions": {
58
63
  "*": {
59
64
  ".": [