import { Glob } from "bun"; import { basename, dirname } from "node:path"; import type { Resource, ModuleDef } from "../types/Resource"; interface ModuleEntry { module: ModuleDef; dir: string; } export async function scanModules(path: string): Promise { const glob = new Glob("*/module.ts"); const entries: ModuleEntry[] = []; for await (const file of glob.scan(path)) { try { const fullPath = `${path}/${file}`; const imported = await import(fullPath); const mod = imported.default; if (!mod?.id || !mod?.name || !mod?.description) continue; entries.push({ module: { id: mod.id, name: mod.name, description: mod.description }, dir: dirname(fullPath), }); } catch { continue; } } return entries; } const CONVENTIONAL_DIRS = ["commands", "events", "buttons", "modals"]; export async function scanResources( module: ModuleDef, dir: string, additionalDirs: string[] = [], ): Promise { const resources: Resource[] = []; const glob = new Glob("**/*.ts"); const dirs = [...CONVENTIONAL_DIRS, ...additionalDirs]; for (const conventionalDir of dirs) { const scanDir = `${dir}/${conventionalDir}`; const inferredType = basename(conventionalDir).replace(/s$/, ""); // "commands" → "command" try { for await (const file of glob.scan(scanDir)) { try { const fullPath = `${scanDir}/${file}`; const imported = await import(fullPath); const exported = imported.default; if (!exported) continue; const resource: Resource = { ...exported, type: exported.type ?? inferredType, origin: module.id, createdAt: new Date(), }; resources.push(resource); } catch { continue; } } } catch { // Directory doesn't exist — skip } } return resources; }