@hyperneutrino/djs-lite 1.3.0 → 1.4.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.
Files changed (2) hide show
  1. package/index.ts +51 -81
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ ApplicationCommandOptionType,
2
3
  ApplicationCommandType,
3
4
  AutocompleteInteraction,
4
5
  ButtonInteraction,
@@ -56,12 +57,12 @@ abstract class Command<T extends BaseApplicationCommandData, U extends CommandIn
56
57
  }
57
58
  }
58
59
 
59
- export class SlashCommand extends Command<ChatInputApplicationCommandData & { type: ApplicationCommandType.ChatInput }, ChatInputCommandInteraction, true> {}
60
- export class UserCommand extends Command<UserApplicationCommandData, UserContextMenuCommandInteraction> {}
61
- export class MessageCommand extends Command<MessageApplicationCommandData, MessageContextMenuCommandInteraction> {}
60
+ export class SlashCommand extends Command<Omit<ChatInputApplicationCommandData, "type">, ChatInputCommandInteraction, true> {}
61
+ export class UserCommand extends Command<Omit<UserApplicationCommandData, "type">, UserContextMenuCommandInteraction> {}
62
+ export class MessageCommand extends Command<Omit<MessageApplicationCommandData, "type">, MessageContextMenuCommandInteraction> {}
62
63
 
63
64
  export class SlashCommandWithSubcommands {
64
- data: Omit<ChatInputApplicationCommandData, "options"> & { type: ApplicationCommandType.ChatInput };
65
+ data: Omit<ChatInputApplicationCommandData, "options" | "type">;
65
66
 
66
67
  constructor(data: typeof this.data) {
67
68
  this.data = data;
@@ -69,7 +70,7 @@ export class SlashCommandWithSubcommands {
69
70
  }
70
71
 
71
72
  export class SubcommandGroup {
72
- data: Omit<ApplicationCommandSubGroupData, "options">;
73
+ data: Omit<ApplicationCommandSubGroupData, "options" | "type">;
73
74
 
74
75
  constructor(data: typeof this.data) {
75
76
  this.data = data;
@@ -77,7 +78,7 @@ export class SubcommandGroup {
77
78
  }
78
79
 
79
80
  export class Subcommand {
80
- data: ApplicationCommandSubCommandData;
81
+ data: Omit<ApplicationCommandSubCommandData, "type">;
81
82
  handler: Handler<ChatInputCommandInteraction>;
82
83
 
83
84
  constructor({ handler, ...data }: typeof this.data & { handler: Subcommand["handler"] }) {
@@ -123,7 +124,7 @@ async function importAll(
123
124
  if (file.isDirectory()) return;
124
125
 
125
126
  const absolutePath = path.resolve(file.parentPath, file.name);
126
- const relativePath = path.relative(path.resolve(directory), absolutePath);
127
+ const relativePath = path.join(directory, path.relative(path.resolve(directory), absolutePath));
127
128
 
128
129
  const { default: item } = await import(absolutePath);
129
130
 
@@ -143,7 +144,7 @@ export async function loadSubcommands(directory: string): Promise<{
143
144
 
144
145
  await importAll({ directory, recursive: false }, async ({ file, relativePath, item }) => {
145
146
  if (item instanceof Subcommand) {
146
- options.push(item.data);
147
+ options.push({ ...item.data, type: ApplicationCommandOptionType.Subcommand });
147
148
  handlers.set(item.data.name, item.handler);
148
149
  } else throw new Error(`Loading commands failed: export from ${relativePath} (third-level in commands folder) was not an instance of Subcommand.`);
149
150
 
@@ -158,18 +159,18 @@ export async function loadSubcommandsAndGroups(directory: string): Promise<{
158
159
  options: (ApplicationCommandSubGroupData | ApplicationCommandSubCommandData)[];
159
160
  handler: Handler<ChatInputCommandInteraction>;
160
161
  }> {
161
- if (!(await fs.exists(directory))) throw new Error(`Loading subcomands/groups failed: ${directory} is required but could not be found.`);
162
+ if (!(await fs.exists(directory))) throw new Error(`Loading subcommands/groups failed: ${directory} is required but could not be found.`);
162
163
 
163
164
  const options: (ApplicationCommandSubGroupData | ApplicationCommandSubCommandData)[] = [];
164
165
  const handlers = new Map<string, Handler<ChatInputCommandInteraction>>();
165
166
 
166
167
  await importAll({ directory, recursive: false }, async ({ file, relativePath, item }) => {
167
168
  if (item instanceof Subcommand) {
168
- options.push(item.data);
169
+ options.push({ ...item.data, type: ApplicationCommandOptionType.Subcommand });
169
170
  handlers.set(`/${item.data.name}`, item.handler);
170
171
  } else if (item instanceof SubcommandGroup) {
171
172
  const subcommands = await loadSubcommands(relativePath.replace(/\.[^/.]+$/, ""));
172
- options.push({ ...item.data, options: subcommands.options });
173
+ options.push({ ...item.data, type: ApplicationCommandOptionType.SubcommandGroup, options: subcommands.options });
173
174
  subcommands.handlers.entries().forEach(([key, handler]) => handlers.set(`${item.data.name}/${key}`, handler));
174
175
  } else
175
176
  throw new Error(
@@ -187,8 +188,6 @@ export async function loadSubcommandsAndGroups(directory: string): Promise<{
187
188
  }
188
189
 
189
190
  export async function loadCommands(client: Client<true>, directory: string, guildId?: string) {
190
- const files = await fs.readdir(path.resolve(directory), { recursive: false, withFileTypes: true });
191
-
192
191
  const commandData: (ChatInputApplicationCommandData | UserApplicationCommandData | MessageApplicationCommandData)[] = [];
193
192
 
194
193
  const slashCommandHandlers = new Map<string, Handler<ChatInputCommandInteraction>>();
@@ -197,36 +196,28 @@ export async function loadCommands(client: Client<true>, directory: string, guil
197
196
 
198
197
  const slashCommandAutocompletes = new Map<string, Handler<AutocompleteInteraction>>();
199
198
 
200
- await Promise.all(
201
- files.map(async (file) => {
202
- if (file.isDirectory()) return;
203
-
204
- const absolutePath = path.resolve(file.parentPath, file.name);
205
- const relativePath = path.relative(path.resolve(directory), absolutePath);
206
-
207
- const { default: item } = await import(absolutePath);
199
+ await importAll({ directory, recursive: false }, async ({ file, relativePath, item }) => {
200
+ if (item instanceof SlashCommand) {
201
+ commandData.push({ ...item.data, type: ApplicationCommandType.ChatInput });
202
+ slashCommandHandlers.set(item.data.name, item.handler);
203
+ if (item.autocomplete) slashCommandAutocompletes.set(item.data.name, item.autocomplete);
204
+ } else if (item instanceof UserCommand) {
205
+ commandData.push({ ...item.data, type: ApplicationCommandType.User });
206
+ userCommandHandlers.set(item.data.name, item.handler);
207
+ } else if (item instanceof MessageCommand) {
208
+ commandData.push({ ...item.data, type: ApplicationCommandType.Message });
209
+ messageCommandHandlers.set(item.data.name, item.handler);
210
+ } else if (item instanceof SlashCommandWithSubcommands) {
211
+ const { options, handler } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
212
+ commandData.push({ ...item.data, options });
213
+ slashCommandHandlers.set(item.data.name, handler);
214
+ } else {
215
+ throw new Error(`Loading commands failed: export from ${relativePath} was not an instance of <Type>Command.`);
216
+ }
208
217
 
209
- if (item instanceof SlashCommand) {
210
- slashCommandHandlers.set(item.data.name, item.handler);
211
- if (item.autocomplete) slashCommandAutocompletes.set(item.data.name, item.autocomplete);
212
- } else if (item instanceof UserCommand) {
213
- userCommandHandlers.set(item.data.name, item.handler);
214
- } else if (item instanceof MessageCommand) {
215
- messageCommandHandlers.set(item.data.name, item.handler);
216
- } else if (item instanceof SlashCommandWithSubcommands) {
217
- const { options, handler } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
218
- commandData.push({ ...item.data, options });
219
- slashCommandHandlers.set(item.data.name, handler);
220
- } else {
221
- throw new Error(`Loading commands failed: export from ${relativePath} was not an instance of <Type>Command.`);
222
- }
223
-
224
- if (item.data.name !== file.name.replace(/.[^/.]+$/, ""))
225
- throw new Error(`Code style enforcement: name exported from ${relativePath} does not match the filename`);
226
-
227
- commandData.push(item.data);
228
- }),
229
- );
218
+ if (item.data.name !== file.name.replace(/.[^/.]+$/, ""))
219
+ throw new Error(`Code style enforcement: name exported from ${relativePath} does not match the filename`);
220
+ });
230
221
 
231
222
  client.on(Events.InteractionCreate, (interaction) => {
232
223
  if (interaction.isChatInputCommand()) slashCommandHandlers.get(interaction.commandName)?.(interaction);
@@ -246,8 +237,6 @@ export async function loadCommands(client: Client<true>, directory: string, guil
246
237
  }
247
238
 
248
239
  export async function loadInteractions(client: Client, directory: string, argumentSeparator: string = ":") {
249
- const files = await fs.readdir(path.resolve(directory), { recursive: true, withFileTypes: true });
250
-
251
240
  const modalHandlers = new Map<string, Handler<ModalSubmitInteraction>>();
252
241
  const buttonHandlers = new Map<string, Handler<ButtonInteraction>>();
253
242
  const stringHandlers = new Map<string, Handler<StringSelectMenuInteraction>>();
@@ -256,26 +245,18 @@ export async function loadInteractions(client: Client, directory: string, argume
256
245
  const mentionHandlers = new Map<string, Handler<MentionableSelectMenuInteraction>>();
257
246
  const channelHandlers = new Map<string, Handler<ChannelSelectMenuInteraction>>();
258
247
 
259
- await Promise.all(
260
- files.map(async (file) => {
261
- if (file.isDirectory()) return;
262
-
263
- const absolutePath = path.resolve(file.parentPath, file.name);
264
- const relativePath = path.relative(path.resolve(directory), absolutePath);
265
- const handlerKey = relativePath.replace(/\.[^/.]+$/, "").replace(/\\/g, "/");
266
-
267
- const { default: item } = await import(absolutePath).catch(() => null);
268
-
269
- if (item instanceof ModalHandler) modalHandlers.set(handlerKey, item.handler);
270
- else if (item instanceof ButtonHandler) buttonHandlers.set(handlerKey, item.handler);
271
- else if (item instanceof StringSelectHandler) stringHandlers.set(handlerKey, item.handler);
272
- else if (item instanceof UserSelectHandler) userHandlers.set(handlerKey, item.handler);
273
- else if (item instanceof RoleSelectHandler) roleHandlers.set(handlerKey, item.handler);
274
- else if (item instanceof MentionSelectHandler) mentionHandlers.set(handlerKey, item.handler);
275
- else if (item instanceof ChannelSelectHandler) channelHandlers.set(handlerKey, item.handler);
276
- else throw new Error(`Loading interactions failed: export from ${relativePath} was not an instance of <InteractionType>Handler.`);
277
- }),
278
- );
248
+ await importAll({ directory, recursive: true }, async ({ file, relativePath, item }) => {
249
+ const handlerKey = relativePath.replace(/\.[^/.]+$/, "").replace(/\\/g, "/");
250
+
251
+ if (item instanceof ModalHandler) modalHandlers.set(handlerKey, item.handler);
252
+ else if (item instanceof ButtonHandler) buttonHandlers.set(handlerKey, item.handler);
253
+ else if (item instanceof StringSelectHandler) stringHandlers.set(handlerKey, item.handler);
254
+ else if (item instanceof UserSelectHandler) userHandlers.set(handlerKey, item.handler);
255
+ else if (item instanceof RoleSelectHandler) roleHandlers.set(handlerKey, item.handler);
256
+ else if (item instanceof MentionSelectHandler) mentionHandlers.set(handlerKey, item.handler);
257
+ else if (item instanceof ChannelSelectHandler) channelHandlers.set(handlerKey, item.handler);
258
+ else throw new Error(`Loading interactions failed: export from ${relativePath} was not an instance of <InteractionType>Handler.`);
259
+ });
279
260
 
280
261
  client.on(Events.InteractionCreate, (interaction) => {
281
262
  if (!interaction.isMessageComponent() && !interaction.isModalSubmit()) return;
@@ -294,25 +275,14 @@ export async function loadInteractions(client: Client, directory: string, argume
294
275
  }
295
276
 
296
277
  export async function loadEvents(client: Client, directory: string, recursive: boolean = false) {
297
- const files = await fs.readdir(path.resolve(directory), { recursive, withFileTypes: true });
298
278
  const handlers: Partial<{ [K in keyof ClientEvents]: ((...args: ClientEvents[K]) => unknown)[] }> = {};
299
279
 
300
- await Promise.all(
301
- files.map(async (file) => {
302
- if (file.isDirectory()) return;
303
-
304
- const absolutePath = path.resolve(file.parentPath, file.name);
305
-
306
- const { default: item } = await import(absolutePath);
307
-
308
- if (item instanceof EventHandler) (handlers[item.event as keyof ClientEvents] ??= []).push(item.handler);
309
- else {
310
- throw new Error(
311
- `Loading events failed: export from ${path.relative(path.resolve(directory), absolutePath)} was not an instance of EventHandler<T>.`,
312
- );
313
- }
314
- }),
315
- );
280
+ await importAll({ directory, recursive }, async ({ relativePath, item }) => {
281
+ if (item instanceof EventHandler) (handlers[item.event as keyof ClientEvents] ??= []).push(item.handler);
282
+ else {
283
+ throw new Error(`Loading events failed: export from ${relativePath} was not an instance of EventHandler<T>.`);
284
+ }
285
+ });
316
286
 
317
287
  Object.entries(handlers).forEach(([key, handlers]) => client.on(key, (...args) => handlers.forEach((handler) => (handler as any)(...args))));
318
288
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hyperneutrino/djs-lite",
3
3
  "private": false,
4
- "version": "1.3.0",
4
+ "version": "1.4.1",
5
5
  "module": "index.ts",
6
6
  "type": "module",
7
7
  "devDependencies": {