@hyperneutrino/djs-lite 1.4.0 → 1.4.2

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 +43 -77
  2. package/package.json +1 -1
package/index.ts CHANGED
@@ -29,8 +29,6 @@ import type { Dirent } from "node:fs";
29
29
  import fs from "node:fs/promises";
30
30
  import path from "node:path";
31
31
 
32
- // TODO: comments (requires some refactoring of types to do right)
33
-
34
32
  process.on("uncaughtException", (err) => console.error(err));
35
33
 
36
34
  type Handler<T extends CommandInteraction | AutocompleteInteraction | MessageComponentInteraction | ModalSubmitInteraction> = (
@@ -124,7 +122,7 @@ async function importAll(
124
122
  if (file.isDirectory()) return;
125
123
 
126
124
  const absolutePath = path.resolve(file.parentPath, file.name);
127
- const relativePath = path.relative(path.resolve(directory), absolutePath);
125
+ const relativePath = path.join(directory, path.relative(path.resolve(directory), absolutePath));
128
126
 
129
127
  const { default: item } = await import(absolutePath);
130
128
 
@@ -133,7 +131,7 @@ async function importAll(
133
131
  );
134
132
  }
135
133
 
136
- export async function loadSubcommands(directory: string): Promise<{
134
+ async function loadSubcommands(directory: string): Promise<{
137
135
  options: ApplicationCommandSubCommandData[];
138
136
  handlers: Map<string, Handler<ChatInputCommandInteraction>>;
139
137
  }> {
@@ -155,11 +153,11 @@ export async function loadSubcommands(directory: string): Promise<{
155
153
  return { options, handlers };
156
154
  }
157
155
 
158
- export async function loadSubcommandsAndGroups(directory: string): Promise<{
156
+ async function loadSubcommandsAndGroups(directory: string): Promise<{
159
157
  options: (ApplicationCommandSubGroupData | ApplicationCommandSubCommandData)[];
160
158
  handler: Handler<ChatInputCommandInteraction>;
161
159
  }> {
162
- if (!(await fs.exists(directory))) throw new Error(`Loading subcomands/groups failed: ${directory} is required but could not be found.`);
160
+ if (!(await fs.exists(directory))) throw new Error(`Loading subcommands/groups failed: ${directory} is required but could not be found.`);
163
161
 
164
162
  const options: (ApplicationCommandSubGroupData | ApplicationCommandSubCommandData)[] = [];
165
163
  const handlers = new Map<string, Handler<ChatInputCommandInteraction>>();
@@ -188,8 +186,6 @@ export async function loadSubcommandsAndGroups(directory: string): Promise<{
188
186
  }
189
187
 
190
188
  export async function loadCommands(client: Client<true>, directory: string, guildId?: string) {
191
- const files = await fs.readdir(path.resolve(directory), { recursive: false, withFileTypes: true });
192
-
193
189
  const commandData: (ChatInputApplicationCommandData | UserApplicationCommandData | MessageApplicationCommandData)[] = [];
194
190
 
195
191
  const slashCommandHandlers = new Map<string, Handler<ChatInputCommandInteraction>>();
@@ -198,37 +194,28 @@ export async function loadCommands(client: Client<true>, directory: string, guil
198
194
 
199
195
  const slashCommandAutocompletes = new Map<string, Handler<AutocompleteInteraction>>();
200
196
 
201
- await Promise.all(
202
- files.map(async (file) => {
203
- if (file.isDirectory()) return;
204
-
205
- const absolutePath = path.resolve(file.parentPath, file.name);
206
- const relativePath = path.relative(path.resolve(directory), absolutePath);
207
-
208
- const { default: item } = await import(absolutePath);
197
+ await importAll({ directory, recursive: false }, async ({ file, relativePath, item }) => {
198
+ if (item instanceof SlashCommand) {
199
+ commandData.push({ ...item.data, type: ApplicationCommandType.ChatInput });
200
+ slashCommandHandlers.set(item.data.name, item.handler);
201
+ if (item.autocomplete) slashCommandAutocompletes.set(item.data.name, item.autocomplete);
202
+ } else if (item instanceof UserCommand) {
203
+ commandData.push({ ...item.data, type: ApplicationCommandType.User });
204
+ userCommandHandlers.set(item.data.name, item.handler);
205
+ } else if (item instanceof MessageCommand) {
206
+ commandData.push({ ...item.data, type: ApplicationCommandType.Message });
207
+ messageCommandHandlers.set(item.data.name, item.handler);
208
+ } else if (item instanceof SlashCommandWithSubcommands) {
209
+ const { options, handler } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
210
+ commandData.push({ ...item.data, options });
211
+ slashCommandHandlers.set(item.data.name, handler);
212
+ } else {
213
+ throw new Error(`Loading commands failed: export from ${relativePath} was not an instance of <Type>Command.`);
214
+ }
209
215
 
210
- if (item instanceof SlashCommand) {
211
- commandData.push({ ...item.data, type: ApplicationCommandType.ChatInput });
212
- slashCommandHandlers.set(item.data.name, item.handler);
213
- if (item.autocomplete) slashCommandAutocompletes.set(item.data.name, item.autocomplete);
214
- } else if (item instanceof UserCommand) {
215
- commandData.push({ ...item.data, type: ApplicationCommandType.User });
216
- userCommandHandlers.set(item.data.name, item.handler);
217
- } else if (item instanceof MessageCommand) {
218
- commandData.push({ ...item.data, type: ApplicationCommandType.Message });
219
- messageCommandHandlers.set(item.data.name, item.handler);
220
- } else if (item instanceof SlashCommandWithSubcommands) {
221
- const { options, handler } = await loadSubcommandsAndGroups(relativePath.replace(/\.[^/.]+$/, ""));
222
- commandData.push({ ...item.data, options });
223
- slashCommandHandlers.set(item.data.name, handler);
224
- } else {
225
- throw new Error(`Loading commands failed: export from ${relativePath} was not an instance of <Type>Command.`);
226
- }
227
-
228
- if (item.data.name !== file.name.replace(/.[^/.]+$/, ""))
229
- throw new Error(`Code style enforcement: name exported from ${relativePath} does not match the filename`);
230
- }),
231
- );
216
+ if (item.data.name !== file.name.replace(/.[^/.]+$/, ""))
217
+ throw new Error(`Code style enforcement: name exported from ${relativePath} does not match the filename`);
218
+ });
232
219
 
233
220
  client.on(Events.InteractionCreate, (interaction) => {
234
221
  if (interaction.isChatInputCommand()) slashCommandHandlers.get(interaction.commandName)?.(interaction);
@@ -248,8 +235,6 @@ export async function loadCommands(client: Client<true>, directory: string, guil
248
235
  }
249
236
 
250
237
  export async function loadInteractions(client: Client, directory: string, argumentSeparator: string = ":") {
251
- const files = await fs.readdir(path.resolve(directory), { recursive: true, withFileTypes: true });
252
-
253
238
  const modalHandlers = new Map<string, Handler<ModalSubmitInteraction>>();
254
239
  const buttonHandlers = new Map<string, Handler<ButtonInteraction>>();
255
240
  const stringHandlers = new Map<string, Handler<StringSelectMenuInteraction>>();
@@ -258,26 +243,18 @@ export async function loadInteractions(client: Client, directory: string, argume
258
243
  const mentionHandlers = new Map<string, Handler<MentionableSelectMenuInteraction>>();
259
244
  const channelHandlers = new Map<string, Handler<ChannelSelectMenuInteraction>>();
260
245
 
261
- await Promise.all(
262
- files.map(async (file) => {
263
- if (file.isDirectory()) return;
264
-
265
- const absolutePath = path.resolve(file.parentPath, file.name);
266
- const relativePath = path.relative(path.resolve(directory), absolutePath);
267
- const handlerKey = relativePath.replace(/\.[^/.]+$/, "").replace(/\\/g, "/");
268
-
269
- const { default: item } = await import(absolutePath).catch(() => null);
270
-
271
- if (item instanceof ModalHandler) modalHandlers.set(handlerKey, item.handler);
272
- else if (item instanceof ButtonHandler) buttonHandlers.set(handlerKey, item.handler);
273
- else if (item instanceof StringSelectHandler) stringHandlers.set(handlerKey, item.handler);
274
- else if (item instanceof UserSelectHandler) userHandlers.set(handlerKey, item.handler);
275
- else if (item instanceof RoleSelectHandler) roleHandlers.set(handlerKey, item.handler);
276
- else if (item instanceof MentionSelectHandler) mentionHandlers.set(handlerKey, item.handler);
277
- else if (item instanceof ChannelSelectHandler) channelHandlers.set(handlerKey, item.handler);
278
- else throw new Error(`Loading interactions failed: export from ${relativePath} was not an instance of <InteractionType>Handler.`);
279
- }),
280
- );
246
+ await importAll({ directory, recursive: true }, async ({ relativePath, item }) => {
247
+ const handlerKey = relativePath.replace(/\.[^/.]+$/, "").replace(/\\/g, "/");
248
+
249
+ if (item instanceof ModalHandler) modalHandlers.set(handlerKey, item.handler);
250
+ else if (item instanceof ButtonHandler) buttonHandlers.set(handlerKey, item.handler);
251
+ else if (item instanceof StringSelectHandler) stringHandlers.set(handlerKey, item.handler);
252
+ else if (item instanceof UserSelectHandler) userHandlers.set(handlerKey, item.handler);
253
+ else if (item instanceof RoleSelectHandler) roleHandlers.set(handlerKey, item.handler);
254
+ else if (item instanceof MentionSelectHandler) mentionHandlers.set(handlerKey, item.handler);
255
+ else if (item instanceof ChannelSelectHandler) channelHandlers.set(handlerKey, item.handler);
256
+ else throw new Error(`Loading interactions failed: export from ${relativePath} was not an instance of <InteractionType>Handler.`);
257
+ });
281
258
 
282
259
  client.on(Events.InteractionCreate, (interaction) => {
283
260
  if (!interaction.isMessageComponent() && !interaction.isModalSubmit()) return;
@@ -296,25 +273,14 @@ export async function loadInteractions(client: Client, directory: string, argume
296
273
  }
297
274
 
298
275
  export async function loadEvents(client: Client, directory: string, recursive: boolean = false) {
299
- const files = await fs.readdir(path.resolve(directory), { recursive, withFileTypes: true });
300
276
  const handlers: Partial<{ [K in keyof ClientEvents]: ((...args: ClientEvents[K]) => unknown)[] }> = {};
301
277
 
302
- await Promise.all(
303
- files.map(async (file) => {
304
- if (file.isDirectory()) return;
305
-
306
- const absolutePath = path.resolve(file.parentPath, file.name);
307
-
308
- const { default: item } = await import(absolutePath);
309
-
310
- if (item instanceof EventHandler) (handlers[item.event as keyof ClientEvents] ??= []).push(item.handler);
311
- else {
312
- throw new Error(
313
- `Loading events failed: export from ${path.relative(path.resolve(directory), absolutePath)} was not an instance of EventHandler<T>.`,
314
- );
315
- }
316
- }),
317
- );
278
+ await importAll({ directory, recursive }, async ({ relativePath, item }) => {
279
+ if (item instanceof EventHandler) (handlers[item.event as keyof ClientEvents] ??= []).push(item.handler);
280
+ else {
281
+ throw new Error(`Loading events failed: export from ${relativePath} was not an instance of EventHandler<T>.`);
282
+ }
283
+ });
318
284
 
319
285
  Object.entries(handlers).forEach(([key, handlers]) => client.on(key, (...args) => handlers.forEach((handler) => (handler as any)(...args))));
320
286
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@hyperneutrino/djs-lite",
3
3
  "private": false,
4
- "version": "1.4.0",
4
+ "version": "1.4.2",
5
5
  "module": "index.ts",
6
6
  "type": "module",
7
7
  "devDependencies": {