diff --git a/.husky/pre-commit b/.husky/pre-commit index de6aa19..9baa6cc 100644 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -1,2 +1,2 @@ #!/usr/bin/env sh -bunx prettier --write . ; bunx eslint --fix . +bunx lint-staged diff --git a/eslint.config.js b/eslint.config.js index fb5d4df..981836f 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -1,53 +1,55 @@ -import js from '@eslint/js'; +import js from "@eslint/js"; +import ts from "typescript-eslint"; export default [ - js.configs.recommended, - { - languageOptions: { - ecmaVersion: 'latest', - }, - rules: { - 'arrow-spacing': ['warn', { before: true, after: true }], - 'brace-style': ['error', 'stroustrup', { allowSingleLine: true }], - 'comma-dangle': ['error', 'always-multiline'], - 'comma-spacing': 'error', - 'comma-style': 'error', - curly: ['error', 'multi-line', 'consistent'], - 'dot-location': ['error', 'property'], - 'handle-callback-err': 'off', - indent: ['error', 'tab'], - 'keyword-spacing': 'error', - 'max-nested-callbacks': ['error', { max: 4 }], - 'max-statements-per-line': ['error', { max: 2 }], - 'no-console': 'off', - 'no-empty-function': 'error', - 'no-floating-decimal': 'error', - 'no-inline-comments': 'error', - 'no-lonely-if': 'error', - 'no-multi-spaces': 'error', - 'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 1, maxBOF: 0 }], - 'no-shadow': ['error', { allow: ['err', 'resolve', 'reject'] }], - 'no-trailing-spaces': ['error'], - 'no-var': 'error', - 'no-undef': 'off', - 'object-curly-spacing': ['error', 'always'], - 'prefer-const': 'error', - quotes: ['error', 'single'], - semi: ['error', 'always'], - 'space-before-blocks': 'error', - 'space-before-function-paren': [ - 'error', - { - anonymous: 'never', - named: 'never', - asyncArrow: 'always', - }, - ], - 'space-in-parens': 'error', - 'space-infix-ops': 'error', - 'space-unary-ops': 'error', - 'spaced-comment': 'error', - yoda: 'error', - }, - }, + js.configs.recommended, + ...ts.configs.recommended, + { + languageOptions: { + ecmaVersion: "latest", + }, + rules: { + "arrow-spacing": ["warn", { before: true, after: true }], + "brace-style": ["error", "stroustrup", { allowSingleLine: true }], + "comma-dangle": ["error", "always-multiline"], + "comma-spacing": "error", + "comma-style": "error", + curly: ["error", "multi-line", "consistent"], + "dot-location": ["error", "property"], + "handle-callback-err": "off", + indent: ["error", "tab"], + "keyword-spacing": "error", + "max-nested-callbacks": ["error", { max: 4 }], + "max-statements-per-line": ["error", { max: 2 }], + "no-console": "off", + "no-empty-function": "error", + "no-floating-decimal": "error", + "no-inline-comments": "error", + "no-lonely-if": "error", + "no-multi-spaces": "error", + "no-multiple-empty-lines": ["error", { max: 2, maxEOF: 1, maxBOF: 0 }], + "no-shadow": ["error", { allow: ["err", "resolve", "reject"] }], + "no-trailing-spaces": ["error"], + "no-var": "error", + "no-undef": "off", + "object-curly-spacing": ["error", "always"], + "prefer-const": "error", + quotes: ["error", "single"], + semi: ["error", "always"], + "space-before-blocks": "error", + "space-before-function-paren": [ + "error", + { + anonymous: "never", + named: "never", + asyncArrow: "always", + }, + ], + "space-in-parens": "error", + "space-infix-ops": "error", + "space-unary-ops": "error", + "spaced-comment": "error", + yoda: "error", + }, + }, ]; diff --git a/package.json b/package.json index 2f3d6a8..7068ea2 100644 --- a/package.json +++ b/package.json @@ -8,12 +8,25 @@ "prepare": "husky" }, "private": true, + "lint-staged": { + "*.{ts,js,cts,mts}": [ + "eslint --fix", + "prettier --write" + ], + "*.{json,md,yml,yaml}": [ + "prettier --write" + ] + }, "devDependencies": { "@types/bun": "latest", "eslint": "^9.33.0", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-prettier": "^5.5.4", "husky": "^9.1.7", "lint-staged": "^16.1.5", - "prisma": "^6.14.0" + "prettier": "^3.6.2", + "prisma": "^6.14.0", + "typescript-eslint": "^8.39.1" }, "peerDependencies": { "typescript": "^5.8.3" diff --git a/src/commands/administration/logs.ts b/src/commands/administration/logs.ts index df84185..7f01161 100644 --- a/src/commands/administration/logs.ts +++ b/src/commands/administration/logs.ts @@ -8,10 +8,6 @@ import { StringSelectMenuInteraction, StringSelectMenuOptionBuilder, SlashCommandBuilder, - ChatInputCommandInteractionActivityType, - channelMention, - roleMention, - PresenceUpdateStatus, MessageFlags, SlashCommandBuilder, EmbedBuilder, @@ -77,7 +73,14 @@ export default { } const choice: string = interaction.options.getString("action"); switch (choice) { - case "logs_show": + case "logs_show": { + if (!userData.isOwner) { + await interaction.reply({ + content: `${emoji.answer.no} | This command is only for owner`, + flags: MessageFlags.Ephemeral, + }); + return; + } if (guildData.logEnable) { const logsData: EmbedBuilder = new EmbedBuilder() .setTitle(`Logs for ${interaction.guild.name}`) @@ -104,7 +107,15 @@ export default { }); } return; - case "logs_auto": + } + case "logs_auto": { + if (!userData.isOwner) { + await interaction.reply({ + content: `${emoji.answer.no} | This command is only for owner`, + flags: MessageFlags.Ephemeral, + }); + return; + } if (guildData.logEnable) { await interaction.reply({ content: `${emoji.answer.error} | The log is already setup on this server`, @@ -133,8 +144,8 @@ export default { const roleSelection = new ActionRowBuilder().addComponents(menu); - let permSelector: EmbedBuilder = new EmbedBuilder() - .setTitle(`Which role will have access`) + const permSelector: EmbedBuilder = new EmbedBuilder() + .setTitle("Which role will have access") .setColor(`${guildData.color}`) .setFooter({ text: guildData.footer, @@ -242,7 +253,7 @@ export default { .map((id) => `- <@&${id}>`) .join("\n"); const autoConfig = new EmbedBuilder() - .setTitle(`The logs category is created`) + .setTitle("The logs category is created") .setDescription( ` This following roles will have access to the logs. @@ -260,6 +271,8 @@ export default { return; }, ); + break; + } default: console.error(`no choice on logs command ${choice}`); return; diff --git a/src/commands/custom/set.ts b/src/commands/custom/set.ts index 8e40b41..27fd334 100644 --- a/src/commands/custom/set.ts +++ b/src/commands/custom/set.ts @@ -1,12 +1,9 @@ import { prisma } from "../../lib/prisma.ts"; import { ActivityType, - userMention, - roleMention, PresenceUpdateStatus, MessageFlags, SlashCommandBuilder, - EmbedBuilder, } from "discord.js"; import emoji from "../../../assets/emoji.json" assert { type: "json" }; @@ -111,23 +108,6 @@ export default { ), ), async execute(interaction: CommandInteraction) { - let guildData: Guild; - try { - guildData = await prisma.guild.findUnique({ - where: { - id: interaction.guild.id, - }, - }); - } catch (err) { - console.error( - `\t⚠️ | Cannot get the database connection!\n\t\t(${err}).`, - ); - await interaction.reply({ - content: `${emoji.answer.error} | Cannot connect to the database`, - flags: MessageFlags.Ephemeral, - }); - return; - } let userData: User; try { userData = await prisma.user.findUnique({ @@ -147,7 +127,7 @@ export default { } const subcommand: string = interaction.options.getSubcommand(); switch (subcommand) { - case "color": + case "color": { if (!userData.isOwner) { await interaction.reply({ content: `${emoji.answer.no} | This command is only for owner`, @@ -180,7 +160,8 @@ export default { flags: MessageFlags.Ephemeral, }); return; - case "footer": + } + case "footer": { if (!userData.isOwner) { await interaction.reply({ content: `${emoji.answer.no} | This command is only for owner`, @@ -213,7 +194,8 @@ export default { flags: MessageFlags.Ephemeral, }); return; - case "pp": + } + case "pp": { if (!userData.isBuyer) { await interaction.reply({ content: `${emoji.answer.no} | This command is only for buyer`, @@ -229,13 +211,17 @@ export default { content: `${emoji.answer.no} | Error during changing the bot profile picture`, flags: MessageFlags.Ephemeral, }); + console.error( + `\t⚠️ | Cannot change the bot profile picture!\n\t\t(${err}).`, + ); } await interaction.reply({ content: `${emoji.answer.yes} | The picture profile of the bot is now updated.`, flags: MessageFlags.Ephemeral, }); return; - case "status": + } + case "status": { if (!userData.isBuyer) { await interaction.reply({ content: `${emoji.answer.no} | This command is only for buyer`, @@ -330,6 +316,7 @@ export default { flags: MessageFlags.Ephemeral, }); return; + } } }, }; diff --git a/src/commands/rank/buyer.ts b/src/commands/rank/buyer.ts index 99ee685..30b9da2 100644 --- a/src/commands/rank/buyer.ts +++ b/src/commands/rank/buyer.ts @@ -1,9 +1,4 @@ -import { - EmbedBuilder, - userMention, - MessageFlags, - SlashCommandBuilder, -} from "discord.js"; +import { EmbedBuilder, MessageFlags, SlashCommandBuilder } from "discord.js"; import { prisma } from "../../lib/prisma.ts"; import emoji from "../../../assets/emoji.json" assert { type: "json" }; @@ -116,7 +111,7 @@ export default { }); } catch (err) { console.error( - `⚠️ | Error when adding ${target.username} to the buyer list`, + `⚠️ | Error when adding ${target.username} to the buyer list\n\t${err}`, ); await interaction.reply({ content: `${emoji.answer.error} | Error when adding ${target.username} to the owner list`, @@ -177,7 +172,7 @@ export default { }); } catch (err) { console.error( - `⚠️ | Error when removing ${target.username} to the username`, + `⚠️ | Error when removing ${target.username} to the buyer list\n\t${err}`, ); return; } diff --git a/src/commands/rank/owner.ts b/src/commands/rank/owner.ts index 66e0cdf..6f69c21 100644 --- a/src/commands/rank/owner.ts +++ b/src/commands/rank/owner.ts @@ -1,9 +1,4 @@ -import { - EmbedBuilder, - userMention, - MessageFlags, - SlashCommandBuilder, -} from "discord.js"; +import { EmbedBuilder, MessageFlags, SlashCommandBuilder } from "discord.js"; import { prisma } from "../../lib/prisma.ts"; import emoji from "../../../assets/emoji.json" assert { type: "json" }; @@ -109,7 +104,7 @@ export default { }); } catch (err) { console.error( - `⚠️ | Error when adding ${target.username} to the username`, + `⚠️ | Error when adding ${target.username} to the owner list\n\t${err}`, ); await interaction.reply({ content: `${emoji.answer.error} | Error when adding ${target.username} to the owner list`, @@ -163,7 +158,7 @@ export default { }); } catch (err) { console.error( - `⚠️ | Error when removing ${target.username} to the username`, + `⚠️ | Error when removing ${target.username} to the owner list\n\t${err}`, ); await interaction.reply({ content: `${emoji.answer.error} | Cannot removing the user from the owner list`, diff --git a/src/commands/rank/whitelist.ts b/src/commands/rank/whitelist.ts index d2dca2a..0f11426 100644 --- a/src/commands/rank/whitelist.ts +++ b/src/commands/rank/whitelist.ts @@ -1,9 +1,4 @@ -import { - EmbedBuilder, - userMention, - MessageFlags, - SlashCommandBuilder, -} from "discord.js"; +import { EmbedBuilder, MessageFlags, SlashCommandBuilder } from "discord.js"; import { prisma } from "../../lib/prisma.ts"; import emoji from "../../../assets/emoji.json" assert { type: "json" }; @@ -223,7 +218,7 @@ export default { ); const toSend: EmbedBuilder = new EmbedBuilder() - .setTitle(`🗞️ | Whitelist`) + .setTitle("🗞️ | Whitelist") .setColor(guildData.color) .setFooter({ text: guildData.footer, diff --git a/src/commands/utils/deleteCategories.ts b/src/commands/utils/deleteCategories.ts index aed931a..608da8f 100644 --- a/src/commands/utils/deleteCategories.ts +++ b/src/commands/utils/deleteCategories.ts @@ -1,11 +1,4 @@ -import { - MessageFlags, - ChatInputCommandInteraction, - CategoryChannel, - ChannelType, - PermissionsBitField, - SlashCommandBuilder, -} from "discord.js"; +import { MessageFlags, ChannelType, SlashCommandBuilder } from "discord.js"; import emoji from "../../../assets/emoji.json" assert { type: "json" }; import { prisma } from "../../lib/prisma.ts"; diff --git a/src/commands/utils/info.ts b/src/commands/utils/info.ts index 4f33086..4493067 100644 --- a/src/commands/utils/info.ts +++ b/src/commands/utils/info.ts @@ -84,7 +84,7 @@ export default { } const subcommand: string = interaction.options.getSubcommand(); switch (subcommand) { - case "user": + case "user": { const targetGlobal: GuildMember = interaction.options.getUser("target") || interaction.user; await targetGlobal.fetch(); @@ -151,7 +151,8 @@ export default { flags: MessageFlags.Ephemeral, }); return; - case "server": + } + case "server": { const guild: Guild = interaction.guild; const serverResult: EmbedBuilder = new EmbedBuilder() .setTitle(`${guild.name} Informations`) @@ -190,6 +191,7 @@ export default { embeds: [serverResult], flags: MessageFlags.Ephemeral, }); + } } }, }; diff --git a/src/events/client/guildCreate.ts b/src/events/client/guildCreate.ts index e929448..2eadf69 100644 --- a/src/events/client/guildCreate.ts +++ b/src/events/client/guildCreate.ts @@ -1,17 +1,9 @@ -import { Events, MessageFlags } from "discord.js"; +import { Events } from "discord.js"; import { prisma } from "../../lib/prisma.ts"; export default { name: Events.GuildCreate, - async execute(guild, client) { - const botData = await prisma.bot.findUnique({ - where: { - id: 1, - }, - include: { - buyers: true, - }, - }); + async execute(guild) { await prisma.guild.upsert({ where: { id: guild.id, @@ -23,8 +15,7 @@ export default { }); const members = await guild.members.fetch(); - let i = 0; - for (const [memberId, member] of members) { + for (const [memberId] of members) { await prisma.user.upsert({ where: { id: memberId, diff --git a/src/events/client/ready.ts b/src/events/client/ready.ts index 1319ed5..e346e3c 100644 --- a/src/events/client/ready.ts +++ b/src/events/client/ready.ts @@ -6,8 +6,7 @@ export default { once: true, async execute(client) { try { - let botData: Bot; - botData = await prisma.bot.findUnique({ + const botData: Bot = await prisma.bot.findUnique({ where: { id: 1, }, diff --git a/src/index.ts b/src/index.ts index c0ed9af..0e852cb 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,7 +3,6 @@ import path from "node:path"; import "dotenv/config"; import { Client, Collection, GatewayIntentBits } from "discord.js"; import { PrismaClient } from "@prisma/client"; -import { deployCommands } from "./internal/deploy-commands.ts"; const prisma = new PrismaClient(); @@ -23,7 +22,7 @@ client.commands = new Collection(); const commandFolderPath = path.join(__dirname, "commands"); const commandFolders = fs.readdirSync(commandFolderPath); -console.log(`\n🔍 | Commands search:`); +console.log("\n🔍 | Commands search:"); for (const folder of commandFolders) { const commandsPath = path.join(commandFolderPath, folder); const commandFiles = fs @@ -48,7 +47,7 @@ console.log("\n\n"); const eventFolderPath = path.join(__dirname, "events"); const eventFolders = fs.readdirSync(eventFolderPath); -console.log(`\n🔍 | Events search:`); +console.log("\n🔍 | Events search:"); for (const folder of eventFolders) { const eventsPath = path.join(eventFolderPath, folder); const eventFiles = fs @@ -97,7 +96,7 @@ client.once("ready", async () => { const members = await guild.members.fetch(); - for (const [memberId, member] of members) { + for (const [memberId] of members) { await prisma.user.upsert({ where: { id: memberId, diff --git a/src/internal/deploy-command.ts b/src/internal/deploy-command.ts index d447a4a..0eabce8 100644 --- a/src/internal/deploy-command.ts +++ b/src/internal/deploy-command.ts @@ -1,12 +1,5 @@ import { REST, Routes } from "discord.js"; -import { pathToFileURL } from "node:url"; -import { - Client, - Collection, - Events, - GatewayIntentBits, - MessageFlags, -} from "discord.js"; +import { Client, Collection, GatewayIntentBits } from "discord.js"; import "dotenv/config"; import fs from "node:fs"; import path from "node:path"; @@ -35,7 +28,7 @@ for (const folder of commandFolders) { commands.push(command.data.toJSON()); } else { console.log( - `⚠️ | A Command is missing a required "data" or "execute" property.`, + '⚠️ | A Command is missing a required "data" or "execute" property.', ); } }