From 91d45846d6c840af3f522a7bd7c2c146053cd839 Mon Sep 17 00:00:00 2001 From: Compey Date: Mon, 21 Nov 2022 14:26:21 +0530 Subject: [PATCH] feat(framework): javascript template & polishes --- packages/bot/javascript/.env.example | 2 + packages/bot/javascript/.eslintrc.json | 9 ++ packages/bot/javascript/.gitignore | 95 +++++++++++++ packages/bot/javascript/README.md | 22 +++ packages/bot/javascript/package.json | 22 +++ packages/bot/javascript/src/commands/help.js | 47 +++++++ packages/bot/javascript/src/commands/hi.js | 11 ++ packages/bot/javascript/src/events/ready.js | 8 ++ packages/bot/javascript/src/index.js | 7 + .../bot/javascript/src/structures/Client.js | 128 ++++++++++++++++++ .../bot/javascript/src/structures/Command.js | 7 + .../bot/javascript/src/structures/Event.js | 7 + packages/bot/tsconfig.json | 2 +- packages/bot/typescript/.gitignore | 102 ++++++++++++++ .../src/commands/{hi.ts => hello.ts} | 7 +- packages/bot/typescript/src/commands/help.ts | 3 - packages/bot/typescript/src/index.ts | 5 - 17 files changed, 471 insertions(+), 13 deletions(-) create mode 100644 packages/bot/javascript/.env.example create mode 100644 packages/bot/javascript/.eslintrc.json create mode 100644 packages/bot/javascript/.gitignore create mode 100644 packages/bot/javascript/README.md create mode 100644 packages/bot/javascript/package.json create mode 100644 packages/bot/javascript/src/commands/help.js create mode 100644 packages/bot/javascript/src/commands/hi.js create mode 100644 packages/bot/javascript/src/events/ready.js create mode 100644 packages/bot/javascript/src/index.js create mode 100644 packages/bot/javascript/src/structures/Client.js create mode 100644 packages/bot/javascript/src/structures/Command.js create mode 100644 packages/bot/javascript/src/structures/Event.js create mode 100644 packages/bot/typescript/.gitignore rename packages/bot/typescript/src/commands/{hi.ts => hello.ts} (54%) diff --git a/packages/bot/javascript/.env.example b/packages/bot/javascript/.env.example new file mode 100644 index 0000000..fd800a3 --- /dev/null +++ b/packages/bot/javascript/.env.example @@ -0,0 +1,2 @@ +botToken="gapi_TOKEN" # Guilded API Bot Token +botPrefix="$" # Prefix for the bot's commands to use diff --git a/packages/bot/javascript/.eslintrc.json b/packages/bot/javascript/.eslintrc.json new file mode 100644 index 0000000..47a2a32 --- /dev/null +++ b/packages/bot/javascript/.eslintrc.json @@ -0,0 +1,9 @@ +{ + "parserOptions": { + "ecmaVersion": "latest" + }, + + "env": { + "es6": true + } +} \ No newline at end of file diff --git a/packages/bot/javascript/.gitignore b/packages/bot/javascript/.gitignore new file mode 100644 index 0000000..317e330 --- /dev/null +++ b/packages/bot/javascript/.gitignore @@ -0,0 +1,95 @@ +# Dependency directory +node_modules + +# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# OS metadata +.DS_Store +Thumbs.db diff --git a/packages/bot/javascript/README.md b/packages/bot/javascript/README.md new file mode 100644 index 0000000..238cf3c --- /dev/null +++ b/packages/bot/javascript/README.md @@ -0,0 +1,22 @@ +🚀 This is a guilded bot created using [create-guilded-bot](https://github.com/CompeyDev/create-guilded-bot). + +## Getting Started +In order to run the development environment, configure your .env file with the required variables and then execute the following commands: +```bash +npm run dev +# or with yarn +yarn dev +``` + +Your bot should be online. + +You can start editing the commands by adding/modifying files in the `commands` directory. An example help command is provided in +`commands/help.ts`. + +Events can also be customized by adding files to the `events` directory corresponding to the name of the event. See `events/ready.ts` for an example event. + +## Learn More +Since create-guilded-bot uses guilded.js, you can learn more from their [official docs](https://guilded.js.org/). + + +##### ✨ This template is highly inspired by reconlx's [djs-typescript-handler](https://github.com/reconlx/djs-typescript-handler), so give them a star :) diff --git a/packages/bot/javascript/package.json b/packages/bot/javascript/package.json new file mode 100644 index 0000000..76204e2 --- /dev/null +++ b/packages/bot/javascript/package.json @@ -0,0 +1,22 @@ +{ + "name": "guilded.js-javascript", + "version": "0.1.0", + "main": "src/index.js", + "author": "DevComp ", + "license": "MIT", + "private": true, + "scripts": { + "dev": "nodemon -w src/index.js", + "start": "node src/index.js" + }, + "dependencies": { + "dotenv": "^16.0.3", + "glob": "^7.2.0", + "guilded.js": "^0.13.23" + }, + "devDependencies": { + "eslint-config-custom": "workspace:*", + "eslint": "7.32.0", + "nodemon": "^2.0.20" + } +} \ No newline at end of file diff --git a/packages/bot/javascript/src/commands/help.js b/packages/bot/javascript/src/commands/help.js new file mode 100644 index 0000000..8dc2ff4 --- /dev/null +++ b/packages/bot/javascript/src/commands/help.js @@ -0,0 +1,47 @@ +const { Embed } = require('guilded.js'); +const { client } = require(".."); +const { Command } = require("../structures/Command"); + +module.exports = { + Command: new Command({ + name: "help", + description: "Get a list of commands.", + run: async ({ interaction }) => { + const options = interaction.ctx.getOptions() + if (!options) { + let fetchedCmds = await client.getCommands() + + let stringifiedCommands = "" + for (let cmd in fetchedCmds) { + stringifiedCommands += `${fetchedCmds[cmd].name} - ${fetchedCmds[cmd].description}\n` + } + + const menu = new Embed({ + title: "Available commands", + description: stringifiedCommands, + }) + + interaction.ctx.reply(menu) + } else if (options && options.length == 1) { + let fetchedCmds = await client.getCommands() + let stringifiedCommands = "" + for (let cmd in fetchedCmds) { + if (fetchedCmds[cmd].name == options[0]) { + stringifiedCommands += `${fetchedCmds[cmd].name} - ${fetchedCmds[cmd].description}` + const menu = new Embed({ + title: "Available commands", + description: stringifiedCommands, + }) + + interaction.ctx.reply(menu) + return; + } + + } + + interaction.ctx.reply("No such command exists.") + } + + } + }) +} \ No newline at end of file diff --git a/packages/bot/javascript/src/commands/hi.js b/packages/bot/javascript/src/commands/hi.js new file mode 100644 index 0000000..b826cdd --- /dev/null +++ b/packages/bot/javascript/src/commands/hi.js @@ -0,0 +1,11 @@ +const { Command } = require("../structures/Command"); + +module.exports = { + Command: new Command({ + name: "hello", + description: "Make the bot send a hello world message.", + run: async ({ interaction }) => { + interaction.ctx.reply('Hello, world!') + } + }) +} \ No newline at end of file diff --git a/packages/bot/javascript/src/events/ready.js b/packages/bot/javascript/src/events/ready.js new file mode 100644 index 0000000..a71a207 --- /dev/null +++ b/packages/bot/javascript/src/events/ready.js @@ -0,0 +1,8 @@ +const { client } = require("..") +const { Event } = require("../structures/Event") + +module.exports = { + Command: new Event("ready", () => { + console.log(`${client.user.name} is ready!`) + }) +} diff --git a/packages/bot/javascript/src/index.js b/packages/bot/javascript/src/index.js new file mode 100644 index 0000000..6edc193 --- /dev/null +++ b/packages/bot/javascript/src/index.js @@ -0,0 +1,7 @@ +require("dotenv").config(); +const { ExtendedClient } = require("./structures/Client"); +const client = new ExtendedClient() +module.exports = { + client: client +} +client.start(); \ No newline at end of file diff --git a/packages/bot/javascript/src/structures/Client.js b/packages/bot/javascript/src/structures/Client.js new file mode 100644 index 0000000..af87fc2 --- /dev/null +++ b/packages/bot/javascript/src/structures/Client.js @@ -0,0 +1,128 @@ +const { Client, ClientEvents } = require('guilded.js') +const { promisify } = require('util') +const glob = require('glob') +const { Event } = require('./Event') + + +const globPromise = promisify(glob) + +module.exports = { +ExtendedClient: class ExtendedClient extends Client { + constructor() { + // eslint-disable-next-line turbo/no-undeclared-env-vars + super({ token: process.env.botToken }) + } + + start() { + this.registerModules() + this.login() + } + + // Slash commands would be so cool, guilded! + + async importFile(filePath) { + return (require(filePath)).Command; + } + + + async getCommands() { + const commandFiles = await globPromise( + `${__dirname}/../commands/*{.ts,.js}` + ) + const commandsDir = new Object() + + + for (let commandPath of commandFiles) { + const command = await this.importFile(commandPath) + const splitted = commandPath.split("/") + const fileName = splitted[splitted.length - 1] + commandsDir[fileName] = { name: command.name, description: command.description } + } + + return commandsDir + } + + + registerModules() { + this.registerCommands() + this.registerEvents() + } + + + async registerEvents() { + const eventFiles = await globPromise( + `${__dirname}/../events/*{.ts,.js}` + ) + + eventFiles.forEach(async (filePath) => { + const event = await this.importFile( + filePath + ); + this.on(event.event, event.run); + + }); + } + + async validateCommands() { + let commands = await globPromise( + `${__dirname}/../commands/*{.ts,.js}` + ) + let findDuplicates = (arr) => arr.filter((v, i) => arr.indexOf(v) != i) + let cmds = new Array() + commands.forEach(async (commandPath) => { + let imported = await this.importFile(commandPath) + cmds.push(imported.name) + if (findDuplicates(cmds).length !== 0) { + throw new Error("Command names must be unique.") + } + }) + } + + async registerCommands() { + this.validateCommands().then(async () => { + let commandFiles = await globPromise( + `${__dirname}/../commands/*{.ts,.js}` + ) + + this.on("messageCreated", async (message) => { + + // eslint-disable-next-line turbo/no-undeclared-env-vars + if (message.content.startsWith(process.env.botPrefix)) { + for (let filepath of commandFiles) { + const command = await this.importFile(filepath) + const parsed = message.content.split(" ") + const args = parsed.filter((_, i) => { return i > 0 }) + // eslint-disable-next-line turbo/no-undeclared-env-vars + if (command.name === parsed[0].split(process.env.botPrefix)[1]) { + if (!message.serverId) throw new Error("Failed to fetch message serverId!") + const Context = { + meta: + { + user: await this.members.fetch(message.serverId, message.authorId), + raw: message, + }, + ctx: + { + getOptions: () => { + if (args.length != 0) { + return args + } else { + return null + } + }, + reply: (content) => { message.reply(content) } + } + } + command.run({ interaction: Context }) + return; + } + } + + message.reply("Requested command does not exist!") + } + }) + }) + } +} +} + diff --git a/packages/bot/javascript/src/structures/Command.js b/packages/bot/javascript/src/structures/Command.js new file mode 100644 index 0000000..70384a1 --- /dev/null +++ b/packages/bot/javascript/src/structures/Command.js @@ -0,0 +1,7 @@ +module.exports = { + Command: class Command { + constructor(commandOptions) { + Object.assign(this, commandOptions); + } + } +} \ No newline at end of file diff --git a/packages/bot/javascript/src/structures/Event.js b/packages/bot/javascript/src/structures/Event.js new file mode 100644 index 0000000..0698e2e --- /dev/null +++ b/packages/bot/javascript/src/structures/Event.js @@ -0,0 +1,7 @@ +module.exports = { + Event: class Event { + constructor(event, run) { + Object.assign(this, { event: event, run: run }) + } + } +} \ No newline at end of file diff --git a/packages/bot/tsconfig.json b/packages/bot/tsconfig.json index 27188ee..7fda2b9 100644 --- a/packages/bot/tsconfig.json +++ b/packages/bot/tsconfig.json @@ -1,5 +1,5 @@ { "extends": "tsconfig/default.json", - "include": ["**/*.ts", "environment.d.ts"], + "include": ["**/*.ts", "environment.d.ts", "javascript/src/index.js", "javascript/src/structures/Event.js", "javascript/src/structures/Command.js", "javascript/src/structures/Client.js", "javascript/src/events/ready.js", "javascript/src/commands/hi.js"], "exclude": ["node_modules", "**/*.spec.ts"] } diff --git a/packages/bot/typescript/.gitignore b/packages/bot/typescript/.gitignore new file mode 100644 index 0000000..a9b66b1 --- /dev/null +++ b/packages/bot/typescript/.gitignore @@ -0,0 +1,102 @@ +# Dependency directory +node_modules + +# Rest pulled from https://github.com/github/gitignore/blob/master/Node.gitignore +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +jspm_packages/ + +# TypeScript v1 declaration files +typings/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variables file +.env +.env.test + +# parcel-bundler cache (https://parceljs.org/) +.cache + +# next.js build output +.next + +# nuxt.js build output +.nuxt + +# vuepress build output +.vuepress/dist + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# OS metadata +.DS_Store +Thumbs.db + +# Ignore built ts files +__tests__/runner/* + +# TypeScript build output +dist +dist/* diff --git a/packages/bot/typescript/src/commands/hi.ts b/packages/bot/typescript/src/commands/hello.ts similarity index 54% rename from packages/bot/typescript/src/commands/hi.ts rename to packages/bot/typescript/src/commands/hello.ts index bc22dac..d701562 100644 --- a/packages/bot/typescript/src/commands/hi.ts +++ b/packages/bot/typescript/src/commands/hello.ts @@ -1,11 +1,10 @@ -import { Embed } from "guilded.js"; import { client } from ".."; import { Command } from "../structures/Command"; export default new Command({ - name: "hi", - description: "me when.", + name: "hello", + description: "Make the bot send a hello world message.", run: async ({ interaction }) => { - interaction.ctx.reply('i say hi') + interaction.ctx.reply('Hello, world!') } }) \ No newline at end of file diff --git a/packages/bot/typescript/src/commands/help.ts b/packages/bot/typescript/src/commands/help.ts index 88482a1..8fe9ad6 100644 --- a/packages/bot/typescript/src/commands/help.ts +++ b/packages/bot/typescript/src/commands/help.ts @@ -23,11 +23,8 @@ export default new Command({ interaction.ctx.reply(menu) } else if (options && options.length == 1) { let fetchedCmds = await client.getCommands() - console.log(fetchedCmds) let stringifiedCommands: string = "" for (let cmd in fetchedCmds) { - console.log(fetchedCmds[cmd]) // this only includes `help.ts` for some reason - console.log(fetchedCmds[cmd].name, options[0]) if (fetchedCmds[cmd].name == options[0]) { stringifiedCommands += `${fetchedCmds[cmd].name} - ${fetchedCmds[cmd].description}` const menu = new Embed({ diff --git a/packages/bot/typescript/src/index.ts b/packages/bot/typescript/src/index.ts index bee8612..42b847e 100644 --- a/packages/bot/typescript/src/index.ts +++ b/packages/bot/typescript/src/index.ts @@ -4,8 +4,3 @@ import { ExtendedClient } from "./structures/Client"; export const client = new ExtendedClient(); client.start(); - -import { Event } from "./structures/Event"; -export default new Event("ready", () => { - console.log("Bot is online"); -}); \ No newline at end of file