A powerful and extendable Discord bot, with it's own module system :3 thevoid.cafe/projects/voidy
at develop 74 lines 2.0 kB view raw
1import { Glob } from "bun"; 2import { basename, dirname } from "node:path"; 3import type { Resource, ModuleDef } from "../types/Resource"; 4 5interface ModuleEntry { 6 module: ModuleDef; 7 dir: string; 8} 9 10export async function scanModules(path: string): Promise<ModuleEntry[]> { 11 const glob = new Glob("*/module.ts"); 12 const entries: ModuleEntry[] = []; 13 14 for await (const file of glob.scan(path)) { 15 try { 16 const fullPath = `${path}/${file}`; 17 const imported = await import(fullPath); 18 const mod = imported.default; 19 if (!mod?.id || !mod?.name || !mod?.description) continue; 20 21 entries.push({ 22 module: { id: mod.id, name: mod.name, description: mod.description }, 23 dir: dirname(fullPath), 24 }); 25 } catch { 26 continue; 27 } 28 } 29 30 return entries; 31} 32 33const CONVENTIONAL_DIRS = ["commands", "events", "buttons", "modals"]; 34 35export async function scanResources( 36 module: ModuleDef, 37 dir: string, 38 additionalDirs: string[] = [], 39): Promise<Resource[]> { 40 const resources: Resource[] = []; 41 const glob = new Glob("**/*.ts"); 42 const dirs = [...CONVENTIONAL_DIRS, ...additionalDirs]; 43 44 for (const conventionalDir of dirs) { 45 const scanDir = `${dir}/${conventionalDir}`; 46 const inferredType = basename(conventionalDir).replace(/s$/, ""); // "commands" → "command" 47 48 try { 49 for await (const file of glob.scan(scanDir)) { 50 try { 51 const fullPath = `${scanDir}/${file}`; 52 const imported = await import(fullPath); 53 const exported = imported.default; 54 if (!exported) continue; 55 56 const resource: Resource = { 57 ...exported, 58 type: exported.type ?? inferredType, 59 origin: module.id, 60 createdAt: new Date(), 61 }; 62 63 resources.push(resource); 64 } catch { 65 continue; 66 } 67 } 68 } catch { 69 // Directory doesn't exist — skip 70 } 71 } 72 73 return resources; 74}