From 5e5840ffdfb3570e9f6180c1d605a51558ff7177 Mon Sep 17 00:00:00 2001 From: Tarrgon <61888458+Tarrgon@users.noreply.github.com> Date: Wed, 3 Jun 2026 07:53:58 -0400 Subject: [PATCH] Switch to module --- package.json | 1 + src/index.ts | 12 ++++++------ src/shared/Database.ts | 4 +++- src/utils/commands.ts | 13 +++++++------ src/utils/refresh-commands.ts | 12 ++++++------ src/webserver/index.ts | 20 +++++++++++--------- tsconfig.json | 6 +++--- 7 files changed, 37 insertions(+), 31 deletions(-) diff --git a/package.json b/package.json index 0158b59..311b2ae 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,5 @@ { + "type": "module", "devDependencies": { "@eslint/js": "9.27.0", "@stylistic/eslint-plugin": "4.2.0", diff --git a/src/index.ts b/src/index.ts index 4882582..b1c7ca6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,12 +37,6 @@ const buttons: Handler[] = []; const modals: Handler[] = []; const menus: Handler[] = []; -loadHandlersFrom('commands', commands); -loadHandlersFrom('context-menus', contextMenus); -loadHandlersFrom('buttons', buttons); -loadHandlersFrom('modals', modals); -loadHandlersFrom('menus', menus); - // Due to their reliance on each other, these two events (interactionCreate, and ready) have to stay here. // Alternatively, they can move to another single file. Or use static classes. client.on('interactionCreate', async (interaction) => { @@ -126,6 +120,12 @@ client.on('interactionCreate', async (interaction) => { client.on('clientReady', async () => { console.log(`Logged in as ${client.user!.tag}!`); + await loadHandlersFrom('commands', commands); + await loadHandlersFrom('context-menus', contextMenus); + await loadHandlersFrom('buttons', buttons); + await loadHandlersFrom('modals', modals); + await loadHandlersFrom('menus', menus); + await refreshCommands(client); await initIfNecessary(client, commands); diff --git a/src/shared/Database.ts b/src/shared/Database.ts index 62ffce8..8257efb 100644 --- a/src/shared/Database.ts +++ b/src/shared/Database.ts @@ -1,6 +1,7 @@ -import path from 'path'; +import path, { dirname } from 'path'; import { open, Database as SqliteDatabase } from 'sqlite'; import sqlite3 from 'sqlite3'; +import { fileURLToPath } from 'url'; import { Message } from '../events'; import { AppealMessage, Ban, GithubUserMapping, GuildArraySetting, GuildSetting, GuildSettings, KnowledgebaseItem, LoggedMessage, Note, PrivateHelpTicket, TicketMessage, TicketPhrase } from '../types'; import { serializeMessage, wait } from '../utils'; @@ -141,6 +142,7 @@ export class Database { private static async migrate() { console.log('Starting database migrations'); + const __dirname = dirname(fileURLToPath(import.meta.url)); await Database.db.migrate({ migrationsPath: path.join(__dirname, '..', '..', 'migrations') }); diff --git a/src/utils/commands.ts b/src/utils/commands.ts index ef0018c..46e5d5f 100644 --- a/src/utils/commands.ts +++ b/src/utils/commands.ts @@ -1,17 +1,18 @@ -import fs from 'fs'; -import { Handler } from '../types'; -import path from 'path'; import { Client } from 'discord.js'; +import fs from 'fs'; +import path, { dirname } from 'path'; +import { fileURLToPath, pathToFileURL } from 'url'; +import { Handler } from '../types'; +const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT_DIR = path.resolve(__dirname, '..'); -export function loadHandlersFrom(dir: string, handlerArray: Handler[]) { +export async function loadHandlersFrom(dir: string, handlerArray: Handler[]): Promise { if (!fs.existsSync(`${ROOT_DIR}/${dir}`)) return; const files = fs.readdirSync(`${ROOT_DIR}/${dir}`).filter(file => file.endsWith('.js') || file.endsWith('.ts')); for (const file of files) { - // eslint-disable-next-line @typescript-eslint/no-require-imports - handlerArray.push(require(`${ROOT_DIR}/${dir}/${file}`).default); + handlerArray.push((await import(pathToFileURL(`${ROOT_DIR}/${dir}/${file}`).href)).default); } } diff --git a/src/utils/refresh-commands.ts b/src/utils/refresh-commands.ts index 35de21c..d72017d 100644 --- a/src/utils/refresh-commands.ts +++ b/src/utils/refresh-commands.ts @@ -1,10 +1,11 @@ -import { Client, REST, Routes } from 'discord.js'; -import { config } from '../config'; -import { RESTPostAPIApplicationCommandsJSONBody } from 'discord.js'; +import { Client, REST, RESTPostAPIApplicationCommandsJSONBody, Routes } from 'discord.js'; import fs from 'fs'; +import path, { dirname } from 'path'; +import { fileURLToPath, pathToFileURL } from 'url'; +import { config } from '../config'; import { Command } from '../types'; -import path from 'path'; +const __dirname = dirname(fileURLToPath(import.meta.url)); const ROOT_DIR = path.resolve(__dirname, '..'); const rest = new REST({ version: '10' }).setToken(config.DISCORD_TOKEN!); @@ -21,8 +22,7 @@ export async function refreshCommands(client: Client) { for (const [folderName, files] of Object.entries(commandFiles)) { for (const file of files) { const p = `${ROOT_DIR}/${folderName}/${file}`; - // eslint-disable-next-line @typescript-eslint/no-require-imports - const command: Command = require(p).default; + const command: Command = (await import(pathToFileURL(p).href)).default; if (!command) { console.warn(`File at ${p} has no export. Skipping registering.`); diff --git a/src/webserver/index.ts b/src/webserver/index.ts index 190ff72..ec3e241 100644 --- a/src/webserver/index.ts +++ b/src/webserver/index.ts @@ -1,16 +1,17 @@ +import bodyParser from 'body-parser'; +import crypto from 'crypto'; +import { Client } from 'discord.js'; import express, { Request, Response } from 'express'; +import session from 'express-session'; +import fs from 'fs'; +import MemoryStore from 'memorystore'; +import path, { dirname } from 'path'; +import { fileURLToPath } from 'url'; import { config } from '../config'; import { Database } from '../shared/Database'; -import crypto from 'crypto'; -import session from 'express-session'; -import MemoryStore from 'memorystore'; -import fs from 'fs'; -import path from 'path'; -import { Client } from 'discord.js'; -import bodyParser from 'body-parser'; -import { fixPings, removeIssueLinks } from '../utils/github-user-utils'; -import { logDebug } from '../utils/debug-utils'; import { AltData, comprehensiveAltLookupFromE621, DiscordOAuth2 } from '../utils'; +import { logDebug } from '../utils/debug-utils'; +import { fixPings, removeIssueLinks } from '../utils/github-user-utils'; declare module 'express-session' { interface SessionData { @@ -26,6 +27,7 @@ const PROD_BASE_URL = 'https://discord.e621.net'; const OAUTH_SCOPES = ['identify', 'guilds.join']; +const __dirname = dirname(fileURLToPath(import.meta.url)); const PAGE_TEMPLATE = fs.readFileSync(path.join(__dirname, 'templates', 'page.html'), { encoding: 'utf-8' }); const oauth = new DiscordOAuth2({ diff --git a/tsconfig.json b/tsconfig.json index 3b961de..26cc7ee 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,8 @@ { "compilerOptions": { - "target": "ES2020", - "module": "CommonJS", + "target": "ES2022", + "module": "esnext", + "moduleResolution": "bundler", "forceConsistentCasingInFileNames": false, "inlineSourceMap": true, "outDir": "./dist", @@ -9,7 +10,6 @@ "noImplicitAny": false, "noUnusedLocals": true, "esModuleInterop": true, - "resolveJsonModule": true, "strict": true, "skipLibCheck": true, "lib": [