Compare commits
86 commits
Author | SHA1 | Date | |
---|---|---|---|
523ec0a343 | |||
6bc0cf3d6a | |||
7861829f5d | |||
c526423607 | |||
6d030737fc | |||
acde8b0ccf | |||
7c85aec971 | |||
8e9db75a30 | |||
5676efd969 | |||
16ac225a44 | |||
|
e302f2ee4d | ||
|
f6d57a1fda | ||
c88a15187e | |||
1a8baecfa1 | |||
d3f9fc4fa0 | |||
5ce0960606 | |||
799b04e936 | |||
3a9f1965ae | |||
00a057792b | |||
1b1933a9ce | |||
b10ac37007 | |||
3392e6f031 | |||
a3230cad20 | |||
4e1c418246 | |||
|
10fe4501b5 | ||
|
7e623b4b64 | ||
|
bb848dcec3 | ||
|
044140d58d | ||
|
19e7539e53 | ||
|
c3bcf76aac | ||
|
8ee5c62481 | ||
|
1b036609a9 | ||
|
f11f3954a1 | ||
|
338514ba1e | ||
|
2d2eaadea7 | ||
|
569c22f1f4 | ||
|
1044c57e66 | ||
|
a0a93a4737 | ||
|
e6464d22cb | ||
49d3d9c449 | |||
da96bbefa5 | |||
|
99e375633b | ||
|
abe94ccc72 | ||
|
a9400a95f2 | ||
|
8313e560b4 | ||
|
9579ca837f | ||
|
a5123d6f79 | ||
|
e9112ee00e | ||
|
6e700df0de | ||
|
23858f72fc | ||
|
3100953f2e | ||
|
29f80fba5c | ||
|
7870e35599 | ||
|
33b05d9db6 | ||
|
bec0e4871b | ||
|
1e578728c7 | ||
|
c816f182b2 | ||
|
bebaf30d16 | ||
|
c418ba4d84 | ||
|
80e9daa8dc | ||
|
7840bc9be8 | ||
|
005de0302e | ||
|
a7fc0e2013 | ||
|
4a28665048 | ||
|
b519537072 | ||
|
96dba8c84b | ||
|
e4d87650c4 | ||
|
03a0f6209b | ||
|
cdb1cf9b53 | ||
|
91ff0f0648 | ||
|
4928820e08 | ||
|
ebae6d3336 | ||
|
b37dcf136d | ||
|
e50630e4f4 | ||
|
c1786d1f18 | ||
|
45cd269248 | ||
|
a8aabf99d8 | ||
|
de2d589504 | ||
|
2ec2e81853 | ||
|
c76532db32 | ||
|
75b0f426da | ||
|
e2974e1a0d | ||
|
80122c9bba | ||
|
d8860212d2 | ||
|
44f2f63499 | ||
|
fd61bbf448 |
38 changed files with 4829 additions and 800 deletions
16
.env.template
Normal file
16
.env.template
Normal file
|
@ -0,0 +1,16 @@
|
|||
# Security Warning! Do not commit this file to any VCS!
|
||||
# This is a local file to speed up development process,
|
||||
# so you don't have to change your environment variables.
|
||||
#
|
||||
# This is not applied to `.env.template`!
|
||||
# Template files must be committed to the VCS, but must not contain
|
||||
# any secret values.
|
||||
|
||||
BOT_TOKEN=
|
||||
BOT_PREFIX=v!
|
||||
|
||||
FOLDERS_COMMANDS=commands
|
||||
FOLDERS_EVENTS=events
|
||||
|
||||
COMMANDS_DISABLED=
|
||||
COMMANDS_DISABLED_MESSAGE=This command is disabled.
|
2
.eslintignore
Normal file
2
.eslintignore
Normal file
|
@ -0,0 +1,2 @@
|
|||
node_modules
|
||||
dist
|
19
.eslintrc
Normal file
19
.eslintrc
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"globals": {
|
||||
"exports": "writable",
|
||||
"module": "writable",
|
||||
"require": "writable",
|
||||
"process": "writable",
|
||||
"console": "writable"
|
||||
}
|
||||
}
|
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -106,8 +106,13 @@ dist
|
|||
# VylBot-Core Testing Files
|
||||
commands/
|
||||
events/
|
||||
bot.js
|
||||
config.json
|
||||
/bot.ts
|
||||
|
||||
!tests/__mocks/commands
|
||||
!tests/__mocks/events
|
||||
|
||||
# Linux Environment Files
|
||||
*.swp
|
||||
|
||||
# macOS Environment Files
|
||||
.DS_Store
|
17
.gitlab-ci.yml
Normal file
17
.gitlab-ci.yml
Normal file
|
@ -0,0 +1,17 @@
|
|||
image: node
|
||||
|
||||
stages:
|
||||
- lint
|
||||
- test
|
||||
|
||||
eslint:
|
||||
stage: lint
|
||||
script:
|
||||
- npm install
|
||||
- npm run lint
|
||||
|
||||
jest:
|
||||
stage: test
|
||||
script:
|
||||
- npm install
|
||||
- npm test
|
|
@ -1,4 +1,4 @@
|
|||
bot.js
|
||||
config.json
|
||||
.env
|
||||
bot.ts
|
||||
commands/
|
||||
events/
|
|
@ -61,7 +61,7 @@ representative at an online or offline event.
|
|||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[INSERT CONTACT METHOD].
|
||||
ethan@vylpes.com.
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
|
|
437
CONTRIBUTING.md
437
CONTRIBUTING.md
|
@ -12,6 +12,225 @@ This project and everyone participating in it is governed by the VylBot Core Cod
|
|||
|
||||
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
|
||||
|
||||
You can ask a question about the project by emailing us at `ethan@vylpes.com`.
|
||||
|
||||
You can ask a question about the project in the `#development` channel in the [Discord Server](https://discord.gg/UyAhAVp).
|
||||
|
||||
## What you should know
|
||||
|
||||
### Javascript and Node
|
||||
|
||||
VylBot Core uses [NodeJS](https://nodejs.org/), and therefore Javascript, as its runtime. You should know how to use this.
|
||||
|
||||
### DiscordJS
|
||||
|
||||
VylBot Core uses [DiscordJS](https://discord.js.org/) as its framework. Although you could contribute without much knowledge of this if you know NodeJS well, however it is recommended to know this.
|
||||
|
||||
## Conventions
|
||||
|
||||
There are a few conventions that have developed over time for this project. When you create a pull request a check will be ran making sure that your code follows these conventions.
|
||||
|
||||
We won't accept pull requests unless these checks pass. If yours fail, simply fix what the bot says until it passes and then get a repo member to review your code.
|
||||
|
||||
The rules for the code is based upon [Vylpes' Config Repo](https://github.com/vylpes/Config)
|
||||
|
||||
* Variable names should use **Camel Case**
|
||||
* Functions should put **braces on the same line**
|
||||
* **No comma dangle**, i.e. having a commma after the last item in an object
|
||||
* **Arrow body style** should have braces around the body only when needed
|
||||
* **Arrow parameters** should have brackets around them only when needed
|
||||
* **Arrow spacing** should have a space around the arrow (' => ')
|
||||
* **No var** should be used, instead use either let or const when appropriate
|
||||
|
||||
## How You Can Contribute
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
This section guides you through submitting a bug report for VylBot Core. Following these guidelines helps maintainers and the community understand your report. reproduce the behaviour, and find related reports.
|
||||
|
||||
When you are creating a bug report, please include as many details as possible.
|
||||
|
||||
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
|
||||
|
||||
#### Before Submitting A Bug Report
|
||||
|
||||
* **Perform a search** to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one.
|
||||
|
||||
#### How You Can Submit A (Good) Bug Report
|
||||
|
||||
Bugs are tracked as GitHub issues. After you've determined the bug you're reporting hasn't got a pre-existing **open** issue already, create an issue and provide information from below.
|
||||
|
||||
* **Use a clear and descriptive title** for the issue to indentify the problem.
|
||||
* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started VylBot Core (if you're using your own instance), which command exactly you used, and the output which the bot replied with. If its your own instance, provide information on what the terminal output said, if any.
|
||||
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pastable snippets, which you use in those examples. If you're providing snippets in the issue, use Markdown code blocks.
|
||||
* **Describe the behaviour you observed after following the steps** and point out what exactly is the problem with that behaviour.
|
||||
* **Explain which behaviour you expected to see instead and why.**
|
||||
* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.
|
||||
* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.
|
||||
|
||||
Provide more context by answering these questions:
|
||||
|
||||
* **Did the problem start happening recently** (e.g. after updating to a new version of VylBot Core) or was this always a problem?
|
||||
* If the problem started happening recently, **can you reproduce the problem in an older version of VylBot Core?** What's the most recently version in which the problem doesn't happen? You can download older versions of VylBot Core from the releases page.
|
||||
* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens.
|
||||
|
||||
Include details about your configuration and environment:
|
||||
|
||||
* **Which version of VylBot Core are you using?** You can get the exact version by running the `about` command.
|
||||
* **Do you have any custom commands added to the commands folder?** If you do, provide information on what the command does, and a link to the command file if it exists.
|
||||
|
||||
> **Note:** We do not provide any support on issues caused by custom commands. You are welcome to create an issue if you believe the issue is to do with the base code, but if the error is to do with that custom command we are unable to fix that, you will need to contact the author of that command.
|
||||
|
||||
* **What's the name and version of the OS you're using?**
|
||||
* **Are you running VylBot Core in a virtual machine?** If so, which VM software are you using and which operating systems and versions are used for the host and the guest?
|
||||
* **What version of node do you have installed?** You can get this version by running the `node -v` command in your terminal.
|
||||
* **What does your `config.json` file look like?**
|
||||
|
||||
> **Note:** remember to **not** give out your bot tokens which are inside of the `config.json` file. If you're giving a copy of your configuration remember to delete the tokens from the string and leave the empty.
|
||||
|
||||
* **Are you running the bot in live or dev mode?**
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
This section guides you through submitting an enhancement suggestion for VylBot Core, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions.
|
||||
|
||||
When you are creating an enhancement suggestion, please include as many details as possible. Fill out the suggestion with the steps that you imagine you would take if the feature you're requesting existed.
|
||||
|
||||
#### Before Submitting an Enhancement Suggestion
|
||||
|
||||
* **Check if the feature already exists.** Make sure to check on the latest version and if you can get the desired behaviour using the config options inside of `config.json`
|
||||
* **Perform a search** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
|
||||
#### How Do I Submit A (Good) Enhancement Suggestion?
|
||||
|
||||
Enhancement suggestions are tracked as GitHub issues. After you've determined the feature doesn't already exist or been suggested before, create an issue on that repository and provide the following information:
|
||||
|
||||
* **Use a clear and descriptive title** for the issue to identify the suggestion.
|
||||
* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
|
||||
* **Provide specific examples to demonstrate the steps.** Include copy/pastable snippets which you use in those examples, as Markdown code blocks.
|
||||
* **Describe the current behaviour** and **explain which behaviour you expected to see instead** and why.
|
||||
* **Include screnshots and animated GIFs** which help you demonstrate the steps or point out the part of VylBot Core which the suggestion is related to.
|
||||
* **Explain why this enhancement would be useful** to most VylBot Core users and isn't something that can or should be implemented as a custom command.
|
||||
* **List some other bots where this enhancement exists.**
|
||||
* **Specify which version of VylBot Core you're using.** You can get the exact version by running the `about` command.
|
||||
* **Specify the name and version of the OS you're using.**
|
||||
|
||||
### Your First Code Contribution
|
||||
|
||||
Unsure where to begin contributing to VylBot Core? You can start by looking through these `good first` and `help wanted` issues:
|
||||
|
||||
* [Good first issue](https://github.com/vylpes/vylbot-core/labels/good%20first%20issue) - issues which should only require a few lines of code, and a test or two.
|
||||
* [Help wanted](https://github.com/vylpes/vylbot-core/labels/help%20wanted) - issues which should be a bit more involved than `good first` issues.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
In order to download necessary tools, clone the repository, and install dependencies via `yarn` you need network access.
|
||||
|
||||
You'll need the following tools:
|
||||
|
||||
* Git
|
||||
* NodeJS
|
||||
|
||||
Install and build all of the dependencies using `yarn`
|
||||
|
||||
```bash
|
||||
cd vylbot-core
|
||||
yarn install
|
||||
cp .env.template .env
|
||||
```
|
||||
And then use your text editor of choice to fill in the `.env` file.
|
||||
|
||||
#### Build and Run
|
||||
|
||||
If you want to understand how VylBot Core works or want to debug an issue, you'll want to get the source, build it, and run the tool locally.
|
||||
|
||||
First, fork the VylBot Core repository so that you can make a pull request. Then, clone your fork locally:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your-github-account>/vylbot-core.git
|
||||
```
|
||||
|
||||
Occasionally, you will want to merge changes in the upstream repository (the official code repo) with your fork.
|
||||
|
||||
```bash
|
||||
cd vylbot-core
|
||||
git checkout master
|
||||
git pull https://github.com/vylpes/vylbot-core.git master
|
||||
```
|
||||
|
||||
Manage any merge conflicts, commit them, and then push them to your fork.
|
||||
|
||||
Go into `VylBot Core` and start the bot in dev mode with `npm run dev` or `node bot dev`
|
||||
|
||||
> **Note:** If you have `nodemon` installed on your system you can use this during development so it auto restarts when you make code changes. Instead of the commands above you can then run `nodemon bot dev`.
|
||||
|
||||
#### Pull Requests
|
||||
|
||||
The process described here has several goals:
|
||||
|
||||
* Maintain VylBot Core's quality
|
||||
* Fix problems that are important to users
|
||||
* Engage the community in working toward the best possible VylBot Core
|
||||
* Enable a sustainable system for VylBot Core's maintainers to review contributions
|
||||
|
||||
Please follow these steps to have your contribution considered by maintainers:
|
||||
|
||||
* You mention the issue id which this pull request aims to fix
|
||||
* After you submit your pull request, verify that all status checks are passing.
|
||||
|
||||
> **Note**: If a check fails the pull request it is important that you go and fix these issues, or let us know that you no longer want to work on this issue by commenting on the pull request. Doing this will give you a better chance of having your pull request merged.
|
||||
|
||||
* When the checks have passed a maintainer will review your code and ask for any improvements or questions, and will merge it if they are satisifed.
|
||||
|
||||
While the prerequesites above must be satisifed prior to having your pull reuqest accepted, the reviewer(s) may ask you to complete additional design ork, tests, or other changes before your pull request can be ultimately accepted.
|
||||
|
||||
#### JavaScript Styleguide
|
||||
|
||||
All JavaScript code is linted with `eslint`.
|
||||
|
||||
* Prefer camelcase for variable names
|
||||
* Prefer braces `{` to be on the same line
|
||||
* Prefer no comma `,` dangle
|
||||
* Prefer arrow function bodies to have brances `{}` only when needed
|
||||
* Prefer arrow function parameters to have brackets `()` only when needed
|
||||
* Prefer arrow function arrows `=>` to have a space before and after it
|
||||
* Prefer `let` and `const` over `var`
|
||||
* Prefer template strings over string concatenation
|
||||
* Prefer comma at the end of the line
|
||||
|
||||
As well as eslint's recommended defaults.
|
||||
|
||||
Example
|
||||
|
||||
```ts
|
||||
// hello.ts
|
||||
import { Command, ICommandContext } from "vylbot-core";
|
||||
|
||||
export class hello extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
public override execute(context: ICommandContext) {
|
||||
context.message.reply("Hello");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
# Contributing to VylBot Core
|
||||
|
||||
First off, thanks for taking the time to contribute!
|
||||
|
||||
The following is a set of guidelines for contributing to VylBot Core. These are mostly guidelines, not rules. Use your best judgement, and feel free to propose changes to this document in a pull request.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it is governed by the VylBot Core Code of Conduct. By participating, you are expected to uphold this code.
|
||||
|
||||
## Questions about VylBot Core
|
||||
|
||||
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
|
||||
|
||||
You can ask a question about the project in the `#development` channel in the [Discord Server](https://discord.gg/UyAhAVp).
|
||||
|
||||
## What you should know
|
||||
|
@ -39,6 +258,8 @@ The rules for the code is based upon [Vylpes' Config Repo](https://github.com/vy
|
|||
* **Arrow parameters** should have brackets around them only when needed
|
||||
* **Arrow spacing** should have a space around the arrow (' => ')
|
||||
* **No var** should be used, instead use either let or const when appropriate
|
||||
* **Template Strings** should be used over string concatenation
|
||||
* **Comma Style** should have the commas separating items in a list at the end of the line
|
||||
|
||||
## How You Can Contribute
|
||||
|
||||
|
@ -193,6 +414,8 @@ All JavaScript code is linted with `eslint`.
|
|||
* Prefer arrow function parameters to have brackets `()` only when needed
|
||||
* Prefer arrow function arrows `=>` to have a space before and after it
|
||||
* Prefer `let` and `const` over `var`
|
||||
* Prefer template strngs over string concatenation
|
||||
* Prefer commas separating items in a list to be at the end of the line
|
||||
|
||||
As well as eslint's recommended defaults.
|
||||
|
||||
|
@ -202,218 +425,14 @@ Example
|
|||
function ban (member) {
|
||||
let reason = "Example reason";
|
||||
|
||||
member.ban(reason).then(() => {
|
||||
// handle then here
|
||||
}).catch(err => {
|
||||
// handle error here
|
||||
});
|
||||
}# Contributing to VylBot Core
|
||||
|
||||
First off, thanks for taking the time to contribute!
|
||||
|
||||
The following is a set of guidelines for contributing to VylBot Core. These are mostly guidelines, not rules. Use your best judgement, and feel free to propose changes to this document in a pull request.
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project and everyone participating in it is governed by the VylBot Core Code of Conduct. By participating, you are expected to uphold this code.
|
||||
|
||||
## Questions about VylBot Core
|
||||
|
||||
> **Note:** Please don't file an issue to ask a question. You'll get faster results by using the resources below.
|
||||
|
||||
You can ask a question about the project in the `#development` channel in the [Discord Server](https://discord.gg/UyAhAVp).
|
||||
|
||||
## What you should know
|
||||
|
||||
### Javascript and Node
|
||||
|
||||
VylBot Core uses [NodeJS](https://nodejs.org/), and therefore Javascript, as its runtime. You should know how to use this.
|
||||
|
||||
### DiscordJS
|
||||
|
||||
VylBot Core uses [DiscordJS](https://discord.js.org/) as its framework. Although you could contribute without much knowledge of this if you know NodeJS well, however it is recommended to know this.
|
||||
|
||||
## Conventions
|
||||
|
||||
There are a few conventions that have developed over time for this project. When you create a pull request a check will be ran making sure that your code follows these conventions.
|
||||
|
||||
We won't accept pull requests unless these checks pass. If yours fail, simply fix what the bot says until it passes and then get a repo member to review your code.
|
||||
|
||||
The rules for the code is based upon [Vylpes' Config Repo](https://github.com/vylpes/config)
|
||||
|
||||
* Variable names should use **Camel Case**
|
||||
* Functions should put **braces on the same line**
|
||||
* **No comma dangle**, i.e. having a commma after the last item in an object
|
||||
* **Arrow body style** should have braces around the body only when needed
|
||||
* **Arrow parameters** should have brackets around them only when needed
|
||||
* **Arrow spacing** should have a space around the arrow (' => ')
|
||||
* **No var** should be used, instead use either let or const when appropriate
|
||||
|
||||
## How You Can Contribute
|
||||
|
||||
### Reporting Bugs
|
||||
|
||||
This section guides you through submitting a bug report for VylBot Core. Following these guidelines helps maintainers and the community understand your report. reproduce the behaviour, and find related reports.
|
||||
|
||||
When you are creating a bug report, please include as many details as possible.
|
||||
|
||||
> **Note:** If you find a **Closed** issue that seems like it is the same thing that you're experiencing, open a new issue and include a link to the original issue in the body of your new one.
|
||||
|
||||
#### Before Submitting A Bug Report
|
||||
|
||||
* **Perform a search** to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue instead of opening a new one.
|
||||
|
||||
#### How You Can Submit A (Good) Bug Report
|
||||
|
||||
Bugs are tracked as GitHub issues. After you've determined the bug you're reporting hasn't got a pre-existing **open** issue already, create an issue and provide information from below.
|
||||
|
||||
* **Use a clear and descriptive title** for the issue to indentify the problem.
|
||||
* **Describe the exact steps which reproduce the problem** in as many details as possible. For example, start by explaining how you started VylBot Core (if you're using your own instance), which command exactly you used, and the output which the bot replied with. If its your own instance, provide information on what the terminal output said, if any.
|
||||
* **Provide specific examples to demonstrate the steps**. Include links to files or GitHub projects, or copy/pastable snippets, which you use in those examples. If you're providing snippets in the issue, use Markdown code blocks.
|
||||
* **Describe the behaviour you observed after following the steps** and point out what exactly is the problem with that behaviour.
|
||||
* **Explain which behaviour you expected to see instead and why.**
|
||||
* **Include screenshots and animated GIFs** which show you following the described steps and clearly demonstrate the problem.
|
||||
* **If the problem wasn't triggered by a specific action**, describe what you were doing before the problem happened and share more information using the guidelines below.
|
||||
|
||||
Provide more context by answering these questions:
|
||||
|
||||
* **Did the problem start happening recently** (e.g. after updating to a new version of VylBot Core) or was this always a problem?
|
||||
* If the problem started happening recently, **can you reproduce the problem in an older version of VylBot Core?** What's the most recently version in which the problem doesn't happen? You can download older versions of VylBot Core from the releases page.
|
||||
* **Can you reliably reproduce the issue?** If not, provide details about how often the problem happens and under which conditions it normally happens.
|
||||
|
||||
Include details about your configuration and environment:
|
||||
|
||||
* **Which version of VylBot Core are you using?** You can get the exact version by running the `about` command.
|
||||
* **Do you have any custom commands added to the commands folder?** If you do, provide information on what the command does, and a link to the command file if it exists.
|
||||
|
||||
> **Note:** We do not provide any support on issues caused by custom commands. You are welcome to create an issue if you believe the issue is to do with the base code, but if the error is to do with that custom command we are unable to fix that, you will need to contact the author of that command.
|
||||
|
||||
* **What's the name and version of the OS you're using?**
|
||||
* **Are you running VylBot Core in a virtual machine?** If so, which VM software are you using and which operating systems and versions are used for the host and the guest?
|
||||
* **What version of node do you have installed?** You can get this version by running the `node -v` command in your terminal.
|
||||
* **What does your `config.json` file look like?**
|
||||
|
||||
> **Note:** remember to **not** give out your bot tokens which are inside of the `config.json` file. If you're giving a copy of your configuration remember to delete the tokens from the string and leave the empty.
|
||||
|
||||
* **Are you running the bot in live or dev mode?**
|
||||
|
||||
### Suggesting Enhancements
|
||||
|
||||
This section guides you through submitting an enhancement suggestion for VylBot Core, including completely new features and minor improvements to existing functionality. Following these guidelines helps maintainers and the community understand your suggestion and find related suggestions.
|
||||
|
||||
When you are creating an enhancement suggestion, please include as many details as possible. Fill out the suggestion with the steps that you imagine you would take if the feature you're requesting existed.
|
||||
|
||||
#### Before Submitting an Enhancement Suggestion
|
||||
|
||||
* **Check if the feature already exists.** Make sure to check on the latest version and if you can get the desired behaviour using the config options inside of `config.json`
|
||||
* **Perform a search** to see if the enhancement has already been suggested. If it has, add a comment to the existing issue instead of opening a new one.
|
||||
|
||||
#### How Do I Submit A (Good) Enhancement Suggestion?
|
||||
|
||||
Enhancement suggestions are tracked as GitHub issues. After you've determined the feature doesn't already exist or been suggested before, create an issue on that repository and provide the following information:
|
||||
|
||||
* **Use a clear and descriptive title** for the issue to identify the suggestion.
|
||||
* **Provide a step-by-step description of the suggested enhancement** in as many details as possible.
|
||||
* **Provide specific examples to demonstrate the steps.** Include copy/pastable snippets which you use in those examples, as Markdown code blocks.
|
||||
* **Describe the current behaviour** and **explain which behaviour you expected to see instead** and why.
|
||||
* **Include screnshots and animated GIFs** which help you demonstrate the steps or point out the part of VylBot Core which the suggestion is related to.
|
||||
* **Explain why this enhancement would be useful** to most VylBot Core users and isn't something that can or should be implemented as a custom command.
|
||||
* **List some other bots where this enhancement exists.**
|
||||
* **Specify which version of VylBot Core you're using.** You can get the exact version by running the `about` command.
|
||||
* **Specify the name and version of the OS you're using.**
|
||||
|
||||
### Your First Code Contribution
|
||||
|
||||
Unsure where to begin contributing to VylBot Core? You can start by looking through these `good first` and `help wanted` issues:
|
||||
|
||||
* [Good first issue](https://github.com/GetGravitySoft/VylBot Core/labels/good%20first%20issue) - issues which should only require a few lines of code, and a test or two.
|
||||
* [Help wanted](https://github.com/GetGravitySoft/VylBot Core/labels/help%20wanted) - issues which should be a bit more involved than `good first` issues.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
In order to download necessary tools, clone the repository, and install dependencies via `npm` you need network access.
|
||||
|
||||
You'll need the following tools:
|
||||
|
||||
* Git
|
||||
* NodeJS
|
||||
|
||||
Install and build all of the dependencies using `npm`
|
||||
|
||||
```bash
|
||||
cd VylBot Core
|
||||
npm install
|
||||
cp config.json.template config.json
|
||||
```
|
||||
And then use your text editor of choice to fill in the `config.json` file.
|
||||
|
||||
#### Build and Run
|
||||
|
||||
If you want to understand how VylBot Core works or want to debug an issue, you'll want to get the source, build it, and run the tool locally.
|
||||
|
||||
First, fork the VylBot Core repository so that you can make a pull request. Then, clone your fork locally:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/<your-github-account>/VylBot Core.git
|
||||
```
|
||||
|
||||
Occasionally, you will want to merge changes in the upstream repository (the official code repo) with your fork.
|
||||
|
||||
```bash
|
||||
cd VylBot Core
|
||||
git checkout master
|
||||
git pull https://github.com/getgravitysoft/VylBot Core.git master
|
||||
```
|
||||
|
||||
Manage any merge conflicts, commit them, and then push them to your fork.
|
||||
|
||||
Go into `VylBot Core` and start the bot in dev mode with `npm run dev` or `node bot dev`
|
||||
|
||||
> **Note:** If you have `nodemon` installed on your system you can use this during development so it auto restarts when you make code changes. Instead of the commands above you can then run `nodemon bot dev`.
|
||||
|
||||
#### Pull Requests
|
||||
|
||||
The process described here has several goals:
|
||||
|
||||
* Maintain VylBot Core's quality
|
||||
* Fix problems that are important to users
|
||||
* Engage the community in working toward the best possible VylBot Core
|
||||
* Enable a sustainable system for VylBot Core's maintainers to review contributions
|
||||
|
||||
Please follow these steps to have your contribution considered by maintainers:
|
||||
|
||||
* You mention the issue id which this pull request aims to fix
|
||||
* After you submit your pull request, verify that all status checks are passing.
|
||||
|
||||
> **Note**: If a check fails the pull request it is important that you go and fix these issues, or let us know that you no longer want to work on this issue by commenting on the pull request. Doing this will give you a better chance of having your pull request merged.
|
||||
|
||||
* When the checks have passed a maintainer will review your code and ask for any improvements or questions, and will merge it if they are satisifed.
|
||||
|
||||
While the prerequesites above must be satisifed prior to having your pull reuqest accepted, the reviewer(s) may ask you to complete additional design ork, tests, or other changes before your pull request can be ultimately accepted.
|
||||
|
||||
#### JavaScript Styleguide
|
||||
|
||||
All JavaScript code is linted with `eslint`.
|
||||
|
||||
* Prefer camelcase for variable names
|
||||
* Prefer braces `{` to be on the same line
|
||||
* Prefer no comma `,` dangle
|
||||
* Prefer arrow function bodies to have brances `{}` only when needed
|
||||
* Prefer arrow function parameters to have brackets `()` only when needed
|
||||
* Prefer arrow function arrows `=>` to have a space before and after it
|
||||
* Prefer `let` and `const` over `var`
|
||||
|
||||
As well as eslint's recommended defaults.
|
||||
|
||||
Example
|
||||
|
||||
```js
|
||||
function ban (member) {
|
||||
let reason = "Example reason";
|
||||
let args = [
|
||||
"one",
|
||||
"two"
|
||||
];
|
||||
|
||||
member.ban(reason).then(() => {
|
||||
// handle then here
|
||||
}).catch(err => {
|
||||
// handle error here
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
109
README.md
109
README.md
|
@ -4,41 +4,106 @@ Discord bot client based upon Discord.js
|
|||
|
||||
## Installation
|
||||
|
||||
Download the latest version from the [releases page](https://github.com/Vylpes/vylbot-core/releases).
|
||||
Download the latest version from the [releases page](https://gitlab.vylpes.com/Vylpes/vylbot-core/-/releases).
|
||||
|
||||
Copy the config template file and fill in the strings.
|
||||
Copy the config template file and fill in the values.
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "",
|
||||
"prefix": "",
|
||||
"commands": [
|
||||
""
|
||||
],
|
||||
"events": [
|
||||
""
|
||||
]
|
||||
}
|
||||
```env
|
||||
BOT_TOKEN={TOKEN}
|
||||
BOT_PREFIX=v!
|
||||
|
||||
FOLDERS_COMMANDS=commands
|
||||
FOLDERS_EVENTS=events
|
||||
|
||||
COMMANDS_DISABLED=
|
||||
COMMANDS_DISABLED_MESSAGE=This command is disabled.
|
||||
```
|
||||
|
||||
* **Token:** Your bot's token
|
||||
* **Prefix** The command prefix
|
||||
* **Commands:** An array of the folders which contain your commands
|
||||
* **Events:** An array of the folders which contain your events
|
||||
* **BOT_TOKEN:** Your bot's token, replace {TOKEN} with your bot token.
|
||||
* **BOT_PREFIX:** The command prefix.
|
||||
* **FOLDERS_COMMANDS:** The folder which contains your commands.
|
||||
* **FOLDERS_EVENTS:** The folder which contains your events.
|
||||
* **COMMANDS_DISABLED:** List of command file names that won't run, separated by commas.
|
||||
* **COMMANDS_DISABLED_MESSAGE:** The message which is replied to the user who tries to run a disabled command.
|
||||
|
||||
Make sure that you **DO NOT** put your .env file into VCS!
|
||||
|
||||
## Usage
|
||||
|
||||
Implement the client using something like:
|
||||
|
||||
```js
|
||||
const vylbot = require('vylbot-core');
|
||||
const config = require('config.json');
|
||||
```ts
|
||||
// bot.ts
|
||||
|
||||
const client = new vylbot.client(config);
|
||||
import { CoreClient } from "vylbot-core";
|
||||
|
||||
const client = new CoreClient();
|
||||
client.start();
|
||||
```
|
||||
|
||||
See the `docs` folder for more information on how to use vylbot-core
|
||||
### Writing Commands
|
||||
|
||||
The code below will reply to the user with 'PONG' when they type {PREFIX}ping
|
||||
|
||||
```ts
|
||||
// Ping.ts
|
||||
|
||||
import { Command, ICommandContext } from "vylbot-core";
|
||||
|
||||
export default class Ping extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
this._roles = [ "Moderator" ];
|
||||
this._category = "General";
|
||||
}
|
||||
|
||||
public override execute(context: ICommandContext) {
|
||||
context.message.reply('PONG');
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
* **roles**: An array containing what roles the user needs in order to run the command.
|
||||
* **category**: The category the role is part of, useful for categorising commands together in a help command.
|
||||
|
||||
The `context` parameter contains the following:
|
||||
* **name**: The command name
|
||||
* **args**: An array of arguments supplied with the command
|
||||
* **message**: The Discord Message object for the command message sent
|
||||
|
||||
### Writing Events
|
||||
|
||||
The code below will log to the console 'Member Joined: {USERNAME}' when a member joins a server the bot is in
|
||||
|
||||
```ts
|
||||
// Moderation.ts
|
||||
|
||||
import { Event } from "vylbot-core";
|
||||
import { GuildMember } from "discord.js";
|
||||
|
||||
export class Moderation extends Event {
|
||||
public override guildMemberAdd(member: GuildMember) {
|
||||
console.log(`Member Joined: ${member.tag}`);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The following events are supported:
|
||||
* channelCreate(channel: Channel)
|
||||
* channelDelete(channel: Channel | PartialDMChannel)
|
||||
* channelUpdate(oldChannel: Channel, newChannel: Channel)
|
||||
* guildBanAdd(guild: Guild, user: User)
|
||||
* guildBanRemove(guild: Guild, user: User)
|
||||
* guildCreate(guild: Guild)
|
||||
* guildMemberAdd(member: GuildMember)
|
||||
* guildMemberRemove(member: GuildMember | PartialGuildMember)
|
||||
* guildMemberUpdate(oldMember: GuildMember | PartialGuildMember, newMember: GuildMember)
|
||||
* message(message: Message)
|
||||
* messageDelete(message: Message | PartialMessage)
|
||||
* messageUpdate(oldMessage: Message | PartialMessage, newMessage: Message | PartialMessage)
|
||||
* ready()
|
||||
|
||||
All parameters are supplied from discord.js
|
||||
|
||||
## Contributing
|
||||
|
||||
|
|
132
docs/index.md
132
docs/index.md
|
@ -1,132 +0,0 @@
|
|||
# VylBot Core Documentation
|
||||
|
||||
Welcome to the VylBot Core documentation. In this file we will explain how to setup and use VylBot Core in your project.
|
||||
|
||||
## Contents
|
||||
|
||||
1. Initial Setup
|
||||
2. Configuring the client
|
||||
3. Creating a command
|
||||
4. Handling an event
|
||||
|
||||
## 1. Initial Setup
|
||||
|
||||
To setup the package, download it from `npm`
|
||||
|
||||
```bash
|
||||
cd <project-folder>
|
||||
npm install vylbot-core
|
||||
```
|
||||
|
||||
Add to your .js file
|
||||
|
||||
```js
|
||||
const vylbot = require('vylbot-core');
|
||||
const config = require('config.json');
|
||||
|
||||
const client = new vylbot.client(config);
|
||||
client.start();
|
||||
```
|
||||
|
||||
## 2. Configuring the client
|
||||
|
||||
When creating a new `vylbot.client` object you need to pass through some json configuration. This can be either from a .json file or directly written.
|
||||
|
||||
> **Note:** We recommend using a .json file and adding it to your `.gitignore` file to prevent accidentally publishing your bot token.
|
||||
|
||||
An example configuration:
|
||||
|
||||
```json
|
||||
{
|
||||
"token": "<YOUR-BOT-TOKEN>",
|
||||
"prefix": "!",
|
||||
"commands": [
|
||||
"commands"
|
||||
],
|
||||
"events": [
|
||||
"events"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Make sure the folders that you set for `commands` and `events` exist and are at your project's current working directory.
|
||||
|
||||
## 3. Creating a command
|
||||
|
||||
A basic command goes as follows:
|
||||
|
||||
```js
|
||||
// commands/test.js
|
||||
const { command } = require('vylbot-core');
|
||||
|
||||
class test extends command {
|
||||
constructor() {
|
||||
super("test");
|
||||
super.description = "Test description";
|
||||
super.category = "general";
|
||||
super.requiredConfigs = "link";
|
||||
super.roles = "Moderator";
|
||||
super.roles = "Admin";
|
||||
}
|
||||
|
||||
test(context) {
|
||||
context.message.channel.send("Hello there, " + context.config.link);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = test;
|
||||
```
|
||||
|
||||
1. You create a class and export it using `module.exports` and make it extend the vylbot's `command` class.
|
||||
2. In the `constructor()` you need to call `super(run)`, replacing `run` with a string of the name of the method which will run when the command runs.
|
||||
3. Call any of the `super` variables to give it some description, the current ones you can use are: `description`, `category`, `usage`
|
||||
4. If you want the command to only be allowed to run by people with a role, set the role name in `super.roles`
|
||||
|
||||
> **Note:** You can set more than one role to be required by setting `super.roles` again.
|
||||
|
||||
5. If you want the command to require a variable in the config, set the name in `super.requiredConfigs`
|
||||
|
||||
> **Note:** You can set more than one role to be required by setting `super.requiredConfigs` again.
|
||||
|
||||
6. Create a method using the name you set in `super(run)`, with the `context` as its parameter.
|
||||
|
||||
The `context` parameter will be a JSON object of:
|
||||
|
||||
```json
|
||||
{
|
||||
"command": "<Command Name>",
|
||||
"arguments": "<Command Arguments>",
|
||||
"client": "<Bot Client Object",
|
||||
"message": "Discord.js Message Object",
|
||||
"config": "The command's config (if any)"
|
||||
}
|
||||
```
|
||||
|
||||
The command's config will be stored under the command's name, for example, if a command called `test` has set `super.requiredConfigs = "link"`, it will be set in the config as `test.link`.
|
||||
|
||||
## 4. Handling an event
|
||||
|
||||
A basic event handling goes as follows:
|
||||
|
||||
```js
|
||||
// events/message.js
|
||||
const { event } = require('vylbot-core');
|
||||
|
||||
class message extends event {
|
||||
constructor() {
|
||||
super("message");
|
||||
}
|
||||
|
||||
message(message) {
|
||||
console.log("Message received: " + message.content);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = message;
|
||||
```
|
||||
|
||||
1. You create a class and export it using `module.exports` and make it extend the vylbot's `event` class.
|
||||
2. In the `constructor()` you need to call `super(run)`, replacing `run` with a string of the name of the method which will run when the event gets triggered.
|
||||
3. Create a method using the name you set in `super(run)`, with the parameters being as per your event's paramaters in the discord.js documentation.
|
||||
|
||||
> **Note:** The name of the event file will determine what event it will be triggered on. For example, if you want to have an event trigger everytime a message is sent, put into your event folder a file called `message.js` and follow the steps above.
|
5
jest.config.js
Normal file
5
jest.config.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
/** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */
|
||||
module.exports = {
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
};
|
107
package-lock.json
generated
107
package-lock.json
generated
|
@ -1,107 +0,0 @@
|
|||
{
|
||||
"name": "vylbot-core",
|
||||
"version": "1.0.5",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@discordjs/collection": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
|
||||
"integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
|
||||
},
|
||||
"@discordjs/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"requires": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"discord.js": {
|
||||
"version": "12.3.1",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.3.1.tgz",
|
||||
"integrity": "sha512-mSFyV/mbvzH12UXdS4zadmeUf8IMQOo/YdunubG1wWt1xjWvtaJz/s9CGsFD2B5pTw1W/LXxxUbrQjIZ/xlUdw==",
|
||||
"requires": {
|
||||
"@discordjs/collection": "^0.1.6",
|
||||
"@discordjs/form-data": "^3.0.1",
|
||||
"abort-controller": "^3.0.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"prism-media": "^1.2.2",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"ws": "^7.3.1"
|
||||
}
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"requires": {
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
},
|
||||
"prism-media": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.2.tgz",
|
||||
"integrity": "sha512-I+nkWY212lJ500jLe4tN9tWO7nRiBAVdMv76P9kffZjYhw20raMlW1HSSvS+MLXC9MmbNZCazMrAr+5jEEgTuw=="
|
||||
},
|
||||
"setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz",
|
||||
"integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw=="
|
||||
}
|
||||
}
|
||||
}
|
26
package.json
26
package.json
|
@ -1,15 +1,21 @@
|
|||
{
|
||||
"name": "vylbot-core",
|
||||
"version": "1.0.5",
|
||||
"version": "2.0.3",
|
||||
"description": "A discord client based upon discord.js",
|
||||
"main": "./src/index",
|
||||
"main": "./dist/index",
|
||||
"typings": "./dist",
|
||||
"scripts": {
|
||||
"test": "echo \"No Tests Specified\""
|
||||
"build": "tsc",
|
||||
"test": "jest",
|
||||
"lint": "eslint .",
|
||||
"publish": "np"
|
||||
},
|
||||
"author": "Vylpes",
|
||||
"license": "MIT",
|
||||
"funding": "https://ko-fi.com/vylpes",
|
||||
"dependencies": {
|
||||
"discord.js": "^12.3.1"
|
||||
"discord.js": "^12.3.1",
|
||||
"dotenv": "^10.0.0"
|
||||
},
|
||||
"bugs": "https://github.com/vylpes/vylbot-core/issues",
|
||||
"homepage": "https://github.com/vylpes/vylbot-core",
|
||||
|
@ -18,5 +24,15 @@
|
|||
"bot",
|
||||
"client"
|
||||
],
|
||||
"repository": "github:vylpes/vylbot-core"
|
||||
"repository": "github:vylpes/vylbot-core",
|
||||
"devDependencies": {
|
||||
"@types/jest": "^26.0.24",
|
||||
"@types/node": "^16.3.2",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.2",
|
||||
"@typescript-eslint/parser": "^4.29.2",
|
||||
"eslint": "^7.32.0",
|
||||
"jest": "^27.0.6",
|
||||
"ts-jest": "^27.0.4",
|
||||
"typescript": "^4.3.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
const { Client } = require('discord.js');
|
||||
const { existsSync } = require('fs');
|
||||
|
||||
const events = require('./events');
|
||||
const util = require('./util');
|
||||
|
||||
class client extends Client {
|
||||
constructor(config) {
|
||||
super();
|
||||
this.config = config;
|
||||
this.events = new events();
|
||||
this.util = new util(this);
|
||||
}
|
||||
|
||||
start() {
|
||||
super.on("message", this.events.message);
|
||||
super.on("ready", this.events.ready);
|
||||
super.login(this._config.token);
|
||||
|
||||
this.util.loadEvents();
|
||||
}
|
||||
|
||||
// Config
|
||||
get config() {
|
||||
return this._config;
|
||||
}
|
||||
|
||||
set config(config) {
|
||||
// Validate the config
|
||||
if (this._config) throw "Config has already been set";
|
||||
if (typeof config != "object") throw "Config is not a JSON object";
|
||||
|
||||
if (typeof config.token != "string") throw "Token is not a string";
|
||||
if (typeof config.prefix != "string") throw "Prefix is not a string";
|
||||
|
||||
if (typeof config.commands != "object") throw "Commands is not a string";
|
||||
if (typeof config.events != "object") throw "Events is not a string";
|
||||
|
||||
this._config = config;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = client;
|
32
src/client/client.ts
Normal file
32
src/client/client.ts
Normal file
|
@ -0,0 +1,32 @@
|
|||
import { Client } from "discord.js";
|
||||
import * as dotenv from "dotenv";
|
||||
|
||||
import { Events } from "./events";
|
||||
import { Util } from "./util";
|
||||
|
||||
export class CoreClient extends Client {
|
||||
private _events: Events;
|
||||
private _util: Util;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
dotenv.config();
|
||||
|
||||
this._events = new Events();
|
||||
this._util = new Util();
|
||||
}
|
||||
|
||||
public start() {
|
||||
if (!process.env.BOT_TOKEN) throw "BOT_TOKEN is not defined in .env";
|
||||
if (!process.env.BOT_PREFIX) throw "BOT_PREFIX is not defined in .env";
|
||||
if (!process.env.FOLDERS_COMMANDS) throw "FOLDERS_COMMANDS is not defined in .env";
|
||||
if (!process.env.FOLDERS_EVENTS) throw "FOLDERS_EVENTS is not defined in .env";
|
||||
|
||||
super.on("message", this._events.onMessage);
|
||||
super.on("ready", this._events.onReady);
|
||||
|
||||
super.login(process.env.BOT_TOKEN);
|
||||
|
||||
this._util.loadEvents(this);
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
class event {
|
||||
message(message) {
|
||||
if (!message.guild) return;
|
||||
if (message.author.bot) return;
|
||||
|
||||
let prefix = this.config.prefix;
|
||||
|
||||
if (message.content.substring(0, prefix.length).toLowerCase() == prefix.toLowerCase()) {
|
||||
let args = message.content.substring(prefix.length).split(" ");
|
||||
let name = args.shift();
|
||||
|
||||
this.util.loadCommand(name, args, message);
|
||||
}
|
||||
}
|
||||
|
||||
ready() {
|
||||
console.log("Ready");
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = event;
|
75
src/client/events.ts
Normal file
75
src/client/events.ts
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { Message } from "discord.js";
|
||||
import { IBaseResponse } from "../contracts/IBaseResponse";
|
||||
import { Util } from "./util";
|
||||
|
||||
export interface IEventResponse extends IBaseResponse {
|
||||
context?: {
|
||||
prefix: string;
|
||||
name: string;
|
||||
args: string[];
|
||||
message: Message;
|
||||
}
|
||||
}
|
||||
|
||||
export class Events {
|
||||
private _util: Util;
|
||||
|
||||
constructor() {
|
||||
this._util = new Util();
|
||||
}
|
||||
|
||||
// Emit when a message is sent
|
||||
// Used to check for commands
|
||||
public onMessage(message: Message): IEventResponse {
|
||||
if (!message.guild) return {
|
||||
valid: false,
|
||||
message: "Message was not sent in a guild, ignoring.",
|
||||
};
|
||||
|
||||
if (message.author.bot) return {
|
||||
valid: false,
|
||||
message: "Message was sent by a bot, ignoring.",
|
||||
};
|
||||
|
||||
const prefix = process.env.BOT_PREFIX as string;
|
||||
|
||||
if (message.content.substring(0, prefix.length).toLowerCase() == prefix.toLowerCase()) {
|
||||
const args = message.content.substring(prefix.length).split(" ");
|
||||
const name = args.shift();
|
||||
|
||||
if (!name) return {
|
||||
valid: false,
|
||||
message: "Command name was not found",
|
||||
};
|
||||
|
||||
const res = this._util.loadCommand(name, args, message);
|
||||
|
||||
if (!res.valid) {
|
||||
return {
|
||||
valid: false,
|
||||
message: res.message,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
context: {
|
||||
prefix: prefix,
|
||||
name: name,
|
||||
args: args,
|
||||
message: message,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: "Message was not a command, ignoring.",
|
||||
}
|
||||
}
|
||||
|
||||
// Emit when bot is logged in and ready to use
|
||||
public onReady() {
|
||||
console.log("Ready");
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
const { stat, readdirSync } = require('fs');
|
||||
const { config } = require('process');
|
||||
|
||||
class util {
|
||||
constructor(client) {
|
||||
this._client = client;
|
||||
}
|
||||
|
||||
loadCommand(name, args, message) {
|
||||
for (let c = 0; c < this._client.config.commands.length; c++) {
|
||||
let folder = this._client.config.commands[c];
|
||||
|
||||
stat(`${process.cwd()}/${folder}/${name}.js`, (err, stat) => {
|
||||
if (err == null) {
|
||||
let commandFile = require(`${process.cwd()}/${folder}/${name}.js`);
|
||||
let command = new commandFile();
|
||||
|
||||
let requiredConfigs = command.requiredConfigs;
|
||||
|
||||
for (let i = 0; i < requiredConfigs.length; i++) {
|
||||
if (!this._client.config[name]) throw `${commandFile.name} requires ${requiredConfigs[i]} in it's configuration`;
|
||||
if (!this._client.config[name][requiredConfigs[i]]) throw `${commandFile.name} requires ${requiredConfigs[i]} in it's configuration`;
|
||||
}
|
||||
|
||||
let requiredRoles = command.roles;
|
||||
|
||||
for (let i = 0; i < requiredRoles.length; i++) {
|
||||
if (!message.member.roles.cache.find(role => role.name == requiredRoles[i])) {
|
||||
message.reply(`You require the \`${requiredRoles[i]}\` role to run this command`);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
command[command.run]({
|
||||
"command": name,
|
||||
"arguments": args,
|
||||
"client": this._client,
|
||||
"message": message,
|
||||
"config": config
|
||||
});
|
||||
} else if (err.code === 'ENOENT') {
|
||||
// FILE DOESN'T EXIST
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
loadEvents() {
|
||||
for (let e = 0; e < this._client.config.events.length; e++) {
|
||||
let folder = this._client.config.events[e];
|
||||
|
||||
let eventFiles = readdirSync(`${process.cwd()}/${folder}/`);
|
||||
|
||||
for (let i = 0; i < eventFiles.length; i++) {
|
||||
let eventName = eventFiles[i].split('.')[0];
|
||||
let file = require(`${process.cwd()}/${folder}/${eventName}.js`);
|
||||
|
||||
let event = new file;
|
||||
|
||||
this._client.on(eventName, event[event.run]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = util;
|
131
src/client/util.ts
Normal file
131
src/client/util.ts
Normal file
|
@ -0,0 +1,131 @@
|
|||
// Required Components
|
||||
import { Client, Message } from "discord.js";
|
||||
import { readdirSync, existsSync } from "fs";
|
||||
import { IBaseResponse } from "../contracts/IBaseResponse";
|
||||
import { Command } from "../type/command";
|
||||
import { Event } from "../type/event";
|
||||
import { ICommandContext } from "../contracts/ICommandContext";
|
||||
|
||||
export interface IUtilResponse extends IBaseResponse {
|
||||
context?: {
|
||||
name: string;
|
||||
args: string[];
|
||||
message: Message;
|
||||
}
|
||||
}
|
||||
|
||||
// Util Class
|
||||
export class Util {
|
||||
public loadCommand(name: string, args: string[], message: Message): IUtilResponse {
|
||||
if (!message.member) return {
|
||||
valid: false,
|
||||
message: "Member is not part of message",
|
||||
};
|
||||
|
||||
const disabledCommands = process.env.COMMANDS_DISABLED?.split(',');
|
||||
|
||||
if (disabledCommands?.find(x => x == name)) {
|
||||
message.reply(process.env.COMMANDS_DISABLED_MESSAGE || "This command is disabled.");
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: "Command is disabled",
|
||||
};
|
||||
}
|
||||
|
||||
const folder = process.env.FOLDERS_COMMANDS;
|
||||
|
||||
if (existsSync(`${process.cwd()}/${folder}/`)) {
|
||||
if (existsSync(`${process.cwd()}/${folder}/${name}.ts`)) {
|
||||
const commandFile = require(`${process.cwd()}/${folder}/${name}.ts`).default;
|
||||
const command = new commandFile() as Command;
|
||||
|
||||
const requiredRoles = command._roles;
|
||||
|
||||
if (!command._category) command._category = "none";
|
||||
|
||||
for (const i in requiredRoles) {
|
||||
if (!message.member.roles.cache.find(role => role.name == requiredRoles[i])) {
|
||||
message.reply(`You require the \`${requiredRoles[i]}\` role to run this command`);
|
||||
|
||||
return {
|
||||
valid: false,
|
||||
message: `You require the \`${requiredRoles[i]}\` role to run this command`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const context: ICommandContext = {
|
||||
name: name,
|
||||
args: args,
|
||||
message: message,
|
||||
}
|
||||
|
||||
// Run the command and pass the command context with it
|
||||
command.execute(context);
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
context: {
|
||||
name: name,
|
||||
args: args,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
valid: false,
|
||||
message: "File does not exist",
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
valid: false,
|
||||
message: "Command folder does not exist",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load the events
|
||||
loadEvents(client: Client): IUtilResponse {
|
||||
const folder = process.env.FOLDERS_EVENTS;
|
||||
|
||||
if (existsSync(`${process.cwd()}/${folder}/`)) {
|
||||
const eventFiles = readdirSync(`${process.cwd()}/${folder}/`);
|
||||
|
||||
for (let i = 0; i < eventFiles.length; i++) {
|
||||
if (eventFiles[i].includes('.ts')) {
|
||||
const eventName = eventFiles[i].split('.')[0];
|
||||
|
||||
const file = require(`${process.cwd()}/${folder}/${eventName}.ts`).default;
|
||||
|
||||
const event = new file() as Event;
|
||||
|
||||
// Load events
|
||||
client.on('channelCreate', event.channelCreate);
|
||||
client.on('channelDelete', event.channelDelete);
|
||||
client.on('channelUpdate', event.channelUpdate);
|
||||
client.on('guildBanAdd', event.guildBanAdd);
|
||||
client.on('guildBanRemove', event.guildBanRemove);
|
||||
client.on('guildCreate', event.guildCreate);
|
||||
client.on('guildMemberAdd', event.guildMemberAdd);
|
||||
client.on('guildMemberRemove', event.guildMemberRemove);
|
||||
client.on('guildMemberUpdate', event.guildMemberUpdate);
|
||||
client.on('message', event.message);
|
||||
client.on('messageDelete', event.messageDelete);
|
||||
client.on('messageUpdate', event.messageUpdate);
|
||||
client.on('ready', event.ready);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
valid: false,
|
||||
message: "Event folder does not exist",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
4
src/contracts/IBaseResponse.ts
Normal file
4
src/contracts/IBaseResponse.ts
Normal file
|
@ -0,0 +1,4 @@
|
|||
export interface IBaseResponse {
|
||||
valid: boolean;
|
||||
message?: string;
|
||||
}
|
7
src/contracts/ICommandContext.ts
Normal file
7
src/contracts/ICommandContext.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { Message } from "discord.js";
|
||||
|
||||
export interface ICommandContext {
|
||||
name: string;
|
||||
args: string[];
|
||||
message: Message;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
const discord = require('discord.js');
|
||||
|
||||
module.exports = {
|
||||
client: require('./client/client'),
|
||||
command: require('./type/command'),
|
||||
event: require('./type/event')
|
||||
}
|
5
src/index.ts
Normal file
5
src/index.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
export { CoreClient } from "./client/client";
|
||||
export { Command } from "./type/command";
|
||||
export { Event } from "./type/event";
|
||||
|
||||
export { ICommandContext } from "./contracts/ICommandContext";
|
107
src/package-lock.json
generated
107
src/package-lock.json
generated
|
@ -1,107 +0,0 @@
|
|||
{
|
||||
"name": "vylbot-core",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@discordjs/collection": {
|
||||
"version": "0.1.6",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz",
|
||||
"integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ=="
|
||||
},
|
||||
"@discordjs/form-data": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@discordjs/form-data/-/form-data-3.0.1.tgz",
|
||||
"integrity": "sha512-ZfFsbgEXW71Rw/6EtBdrP5VxBJy4dthyC0tpQKGKmYFImlmmrykO14Za+BiIVduwjte0jXEBlhSKf0MWbFp9Eg==",
|
||||
"requires": {
|
||||
"asynckit": "^0.4.0",
|
||||
"combined-stream": "^1.0.8",
|
||||
"mime-types": "^2.1.12"
|
||||
}
|
||||
},
|
||||
"abort-controller": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||
"integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
|
||||
"requires": {
|
||||
"event-target-shim": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"asynckit": {
|
||||
"version": "0.4.0",
|
||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
|
||||
},
|
||||
"combined-stream": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||
"requires": {
|
||||
"delayed-stream": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"delayed-stream": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||
},
|
||||
"discord.js": {
|
||||
"version": "12.3.1",
|
||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.3.1.tgz",
|
||||
"integrity": "sha512-mSFyV/mbvzH12UXdS4zadmeUf8IMQOo/YdunubG1wWt1xjWvtaJz/s9CGsFD2B5pTw1W/LXxxUbrQjIZ/xlUdw==",
|
||||
"requires": {
|
||||
"@discordjs/collection": "^0.1.6",
|
||||
"@discordjs/form-data": "^3.0.1",
|
||||
"abort-controller": "^3.0.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"prism-media": "^1.2.2",
|
||||
"setimmediate": "^1.0.5",
|
||||
"tweetnacl": "^1.0.3",
|
||||
"ws": "^7.3.1"
|
||||
}
|
||||
},
|
||||
"event-target-shim": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
|
||||
"integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
|
||||
},
|
||||
"mime-db": {
|
||||
"version": "1.44.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz",
|
||||
"integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg=="
|
||||
},
|
||||
"mime-types": {
|
||||
"version": "2.1.27",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz",
|
||||
"integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==",
|
||||
"requires": {
|
||||
"mime-db": "1.44.0"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
},
|
||||
"prism-media": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/prism-media/-/prism-media-1.2.2.tgz",
|
||||
"integrity": "sha512-I+nkWY212lJ500jLe4tN9tWO7nRiBAVdMv76P9kffZjYhw20raMlW1HSSvS+MLXC9MmbNZCazMrAr+5jEEgTuw=="
|
||||
},
|
||||
"setimmediate": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
|
||||
"integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU="
|
||||
},
|
||||
"tweetnacl": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz",
|
||||
"integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw=="
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.0.tgz",
|
||||
"integrity": "sha512-6ezXvzOZupqKj4jUqbQ9tXuJNo+BR2gU8fFRk3XCP3e0G6WT414u5ELe6Y0vtp7kmSJ3F7YWObSNr1ESsgi4vw=="
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"name": "vylbot-core",
|
||||
"version": "1.0.0",
|
||||
"description": "A discord client based upon discord.js",
|
||||
"main": "./src/index",
|
||||
"scripts": {
|
||||
"test": "echo \"No Tests Specified\""
|
||||
},
|
||||
"author": "Vylpes",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"discord.js": "^12.3.1"
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
class command {
|
||||
constructor(run) {
|
||||
this.run = run;
|
||||
|
||||
this._roles = [];
|
||||
this._requiredConfigs = [];
|
||||
}
|
||||
|
||||
// Description
|
||||
get description() {
|
||||
return this._description;
|
||||
}
|
||||
|
||||
set description(description) {
|
||||
this._description = description;
|
||||
}
|
||||
|
||||
// Category
|
||||
get category() {
|
||||
return this._category;
|
||||
}
|
||||
|
||||
set category(category) {
|
||||
this._category = category;
|
||||
}
|
||||
|
||||
// Usage
|
||||
get usage() {
|
||||
return this._usage;
|
||||
}
|
||||
|
||||
set usage(usage) {
|
||||
this._usage = usage;
|
||||
}
|
||||
|
||||
// Roles
|
||||
get roles() {
|
||||
return this._roles;
|
||||
}
|
||||
|
||||
set roles(role) {
|
||||
this._roles.push(role);
|
||||
}
|
||||
|
||||
// Config
|
||||
get requiredConfigs() {
|
||||
return this._requiredConfigs;
|
||||
}
|
||||
|
||||
set requiredConfigs(conf) {
|
||||
this._requiredConfigs.push(conf);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = command;
|
16
src/type/command.ts
Normal file
16
src/type/command.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import { Message } from "discord.js";
|
||||
import { ICommandContext } from "../contracts/ICommandContext";
|
||||
|
||||
export class Command {
|
||||
public _roles: string[];
|
||||
|
||||
public _category?: string;
|
||||
|
||||
constructor() {
|
||||
this._roles = [];
|
||||
}
|
||||
|
||||
public execute(context: ICommandContext) {
|
||||
|
||||
}
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
class event {
|
||||
constructor(run) {
|
||||
this.run = run;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = event;
|
55
src/type/event.ts
Normal file
55
src/type/event.ts
Normal file
|
@ -0,0 +1,55 @@
|
|||
import { Channel, Guild, User, GuildMember, Message, PartialDMChannel, PartialGuildMember, PartialMessage } from "discord.js";
|
||||
|
||||
export class Event {
|
||||
public channelCreate(channel: Channel) {
|
||||
|
||||
}
|
||||
|
||||
public channelDelete(channel: Channel | PartialDMChannel) {
|
||||
|
||||
}
|
||||
|
||||
public channelUpdate(oldChannel: Channel, newChannel: Channel) {
|
||||
|
||||
}
|
||||
|
||||
public guildBanAdd(guild: Guild, user: User) {
|
||||
|
||||
}
|
||||
|
||||
public guildBanRemove(guild: Guild, user: User) {
|
||||
|
||||
}
|
||||
|
||||
public guildCreate(guild: Guild) {
|
||||
|
||||
}
|
||||
|
||||
public guildMemberAdd(member: GuildMember) {
|
||||
|
||||
}
|
||||
|
||||
public guildMemberRemove(member: GuildMember | PartialGuildMember) {
|
||||
|
||||
}
|
||||
|
||||
public guildMemberUpdate(oldMember: GuildMember | PartialGuildMember, newMember: GuildMember) {
|
||||
|
||||
}
|
||||
|
||||
public message(message: Message) {
|
||||
|
||||
}
|
||||
|
||||
public messageDelete(message: Message | PartialMessage) {
|
||||
|
||||
}
|
||||
|
||||
public messageUpdate(oldMessage: Message | PartialMessage, newMessage: Message | PartialMessage) {
|
||||
|
||||
}
|
||||
|
||||
public ready() {
|
||||
|
||||
}
|
||||
}
|
7
tests/__mocks/commands/noCategory.ts
Normal file
7
tests/__mocks/commands/noCategory.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import { Command } from "../../../src/type/command";
|
||||
|
||||
export default class noCategory extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
}
|
8
tests/__mocks/commands/normal.ts
Normal file
8
tests/__mocks/commands/normal.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { Command } from "../../../src/type/command";
|
||||
|
||||
export default class normal extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
this._category = "General";
|
||||
}
|
||||
}
|
8
tests/__mocks/commands/roles.ts
Normal file
8
tests/__mocks/commands/roles.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { Command } from "../../../src/type/command";
|
||||
|
||||
export default class roles extends Command {
|
||||
constructor() {
|
||||
super();
|
||||
this._roles = [ "Moderator" ];
|
||||
}
|
||||
}
|
5
tests/__mocks/events/normal.ts
Normal file
5
tests/__mocks/events/normal.ts
Normal file
|
@ -0,0 +1,5 @@
|
|||
import { Event } from "../../../src/type/event";
|
||||
|
||||
export default class normal extends Event {
|
||||
public override channelCreate() {}
|
||||
}
|
139
tests/client/client.test.ts
Normal file
139
tests/client/client.test.ts
Normal file
|
@ -0,0 +1,139 @@
|
|||
import { CoreClient } from "../../src/client/client";
|
||||
|
||||
import { Client } from "discord.js";
|
||||
import * as dotenv from "dotenv";
|
||||
import { Events } from "../../src/client/events";
|
||||
import { Util } from "../../src/client/util";
|
||||
|
||||
jest.mock("discord.js");
|
||||
jest.mock("dotenv");
|
||||
jest.mock("../../src/client/events");
|
||||
jest.mock("../../src/client/util");
|
||||
|
||||
describe('Constructor', () => {
|
||||
test('Constructor_ExpectSuccessfulInitialisation', () => {
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(coreClient).toBeInstanceOf(Client);
|
||||
expect(dotenv.config).toBeCalledTimes(1);
|
||||
expect(Events).toBeCalledTimes(1);
|
||||
expect(Util).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Start', () => {
|
||||
test('Given Env Is Valid, Expect Successful Start', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).not.toThrow();
|
||||
expect(coreClient.on).toBeCalledWith("message", expect.any(Function));
|
||||
expect(coreClient.on).toBeCalledWith("ready", expect.any(Function));
|
||||
});
|
||||
|
||||
test('Given BOT_TOKEN Is Null, Expect Failure', () => {
|
||||
process.env = {
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).toThrow("BOT_TOKEN is not defined in .env");
|
||||
});
|
||||
|
||||
test('Given BOT_TOKEN Is Empty, Expect Failure', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: '',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).toThrow("BOT_TOKEN is not defined in .env");
|
||||
});
|
||||
|
||||
test('Given BOT_PREFIX Is Null, Expect Failure', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).toThrow("BOT_PREFIX is not defined in .env");
|
||||
});
|
||||
|
||||
test('Given BOT_PREFIX Is Empty, Expect Failure', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).toThrow("BOT_PREFIX is not defined in .env");
|
||||
});
|
||||
|
||||
test('Given FOLDERS_COMMANDS Is Null, Expect Failure', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).toThrow("FOLDERS_COMMANDS is not defined in .env");
|
||||
});
|
||||
|
||||
test('Given FOLDERS_COMMANDS Is Empty, Expect Failure', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: '',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).toThrow("FOLDERS_COMMANDS is not defined in .env");
|
||||
});
|
||||
|
||||
test('Given FOLDERS_EVENTS Is Null, Expect Failure', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).toThrow("FOLDERS_EVENTS is not defined in .env");
|
||||
});
|
||||
|
||||
test('Given FOLDERS_EVENTS Is Empty, Expect Failure', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: '',
|
||||
}
|
||||
|
||||
const coreClient = new CoreClient();
|
||||
|
||||
expect(() => coreClient.start()).toThrow("FOLDERS_EVENTS is not defined in .env");
|
||||
});
|
||||
});
|
185
tests/client/events.test.ts
Normal file
185
tests/client/events.test.ts
Normal file
|
@ -0,0 +1,185 @@
|
|||
import { Events } from "../../src/client/events";
|
||||
|
||||
import { Message, Client, TextChannel, Guild, SnowflakeUtil, DMChannel } from "discord.js";
|
||||
import { Util } from "../../src/client/util";
|
||||
|
||||
jest.mock("../../src/client/util");
|
||||
|
||||
beforeEach(() => {
|
||||
Util.prototype.loadCommand = jest.fn();
|
||||
});
|
||||
|
||||
describe('OnMessage', () => {
|
||||
test('Given Message Is Valid Expect Message Sent', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
};
|
||||
|
||||
Util.prototype.loadCommand = jest.fn().mockReturnValue({ valid: true });
|
||||
|
||||
const message = {
|
||||
guild: {},
|
||||
author: {
|
||||
bot: false,
|
||||
},
|
||||
content: "!test first",
|
||||
} as unknown as Message;
|
||||
|
||||
const events = new Events();
|
||||
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
|
||||
expect(result.context?.prefix).toBe('!');
|
||||
expect(result.context?.name).toBe('test');
|
||||
expect(result.context?.args.length).toBe(1);
|
||||
expect(result.context?.args[0]).toBe('first');
|
||||
expect(result.context?.message).toBe(message);
|
||||
});
|
||||
|
||||
test('Given Guild Is Null, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
Util.prototype.loadCommand = jest.fn().mockReturnValue({ valid: true });
|
||||
|
||||
const message = {
|
||||
guild: null,
|
||||
author: {
|
||||
bot: false,
|
||||
},
|
||||
content: "!test first",
|
||||
} as unknown as Message;
|
||||
|
||||
const events = new Events();
|
||||
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Message was not sent in a guild, ignoring.");
|
||||
});
|
||||
|
||||
test('Given Author Is A Bot, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
Util.prototype.loadCommand = jest.fn().mockReturnValue({ valid: true });
|
||||
|
||||
const message = {
|
||||
guild: {},
|
||||
author: {
|
||||
bot: true,
|
||||
},
|
||||
content: "!test first",
|
||||
} as unknown as Message;
|
||||
|
||||
const events = new Events();
|
||||
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Message was sent by a bot, ignoring.");
|
||||
});
|
||||
|
||||
test('Given Message Content Was Not A Command, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
Util.prototype.loadCommand = jest.fn().mockReturnValue({ valid: true });
|
||||
|
||||
const message = {
|
||||
guild: {},
|
||||
author: {
|
||||
bot: false,
|
||||
},
|
||||
content: "This is a standard message",
|
||||
} as unknown as Message;
|
||||
|
||||
const events = new Events();
|
||||
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Message was not a command, ignoring.");
|
||||
});
|
||||
|
||||
test('Given Message Had No Command Name, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
Util.prototype.loadCommand = jest.fn().mockReturnValue({ valid: true });
|
||||
|
||||
const message = {
|
||||
guild: {},
|
||||
author: {
|
||||
bot: false,
|
||||
},
|
||||
content: "!",
|
||||
} as unknown as Message;
|
||||
|
||||
const events = new Events();
|
||||
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command name was not found");
|
||||
});
|
||||
|
||||
test('Given Command Failed To Execute, Expect Failed Result', async () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
Util.prototype.loadCommand = jest.fn().mockReturnValue({ valid: false, message: "Command failed" });
|
||||
|
||||
const message = {
|
||||
guild: {},
|
||||
author: {
|
||||
bot: false,
|
||||
},
|
||||
content: "!test first",
|
||||
} as unknown as Message;
|
||||
|
||||
const events = new Events();
|
||||
|
||||
const result = await events.onMessage(message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command failed");
|
||||
});
|
||||
});
|
||||
|
||||
describe('OnReady', () => {
|
||||
test('Expect Console Log', () => {
|
||||
console.log = jest.fn();
|
||||
|
||||
const events = new Events();
|
||||
|
||||
events.onReady();
|
||||
|
||||
expect(console.log).toBeCalledWith("Ready");
|
||||
});
|
||||
});
|
421
tests/client/util.test.ts
Normal file
421
tests/client/util.test.ts
Normal file
|
@ -0,0 +1,421 @@
|
|||
import { Util } from "../../src/client/util";
|
||||
|
||||
import { Client, Guild, Message, Role, SnowflakeUtil, TextChannel, User } from "discord.js";
|
||||
import fs from "fs";
|
||||
|
||||
jest.mock("fs");
|
||||
|
||||
beforeEach(() => {
|
||||
fs.existsSync = jest.fn();
|
||||
});
|
||||
|
||||
describe('LoadCommand', () => {
|
||||
test('Given Successful Exection, Expect Successful Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Given Member Is Null, Expect Failed Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: null
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Member is not part of message");
|
||||
});
|
||||
|
||||
test('Given Folder Does Not Exist, Expect Failed Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(false);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command folder does not exist");
|
||||
});
|
||||
|
||||
test('Given File Does Not Exist, Expect Failed Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValueOnce(true)
|
||||
.mockReturnValue(false);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("File does not exist");
|
||||
});
|
||||
|
||||
test('Given User Does Have Role, Expect Successful Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("roles", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Given User Does Not Have Role, Expect Failed Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(false),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("roles", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("You require the `Moderator` role to run this command");
|
||||
});
|
||||
|
||||
test('Given Command Category Is Null, Expect Successful Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("noCategory", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Given command is set to disabled, Expect command to not fire', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
COMMANDS_DISABLED: 'normal',
|
||||
COMMANDS_DISABLED_MESSAGE: 'disabled',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const messageReply = jest.spyOn(message, 'reply');
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command is disabled");
|
||||
expect(messageReply).toBeCalledWith("disabled");
|
||||
});
|
||||
|
||||
test('Given command COMMANDS_DISABLED_MESSAGE is empty, Expect default message sent', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
COMMANDS_DISABLED: 'normal',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const messageReply = jest.spyOn(message, 'reply');
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command is disabled");
|
||||
expect(messageReply).toBeCalledWith("This command is disabled.");
|
||||
});
|
||||
|
||||
test('Given a different command is disabled, Expect command to still fire', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
COMMANDS_DISABLED: 'anything',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
});
|
||||
|
||||
test('Given a different command is disabled with this one, Expect command to not fire', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
COMMANDS_DISABLED: 'normal,anything,',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
|
||||
const message = {
|
||||
member: {
|
||||
roles: {
|
||||
cache: {
|
||||
find: jest.fn().mockReturnValue(true),
|
||||
}
|
||||
},
|
||||
},
|
||||
reply: jest.fn(),
|
||||
} as unknown as Message;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadCommand("normal", [ "first" ], message);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Command is disabled");
|
||||
});
|
||||
});
|
||||
|
||||
describe('LoadEvents', () => {
|
||||
test('Given Events Are Loaded, Expect Successful Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
fs.readdirSync = jest.fn().mockReturnValue(["normal.ts"]);
|
||||
|
||||
const client = {
|
||||
on: jest.fn(),
|
||||
} as unknown as Client;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadEvents(client);
|
||||
|
||||
const clientOn = jest.spyOn(client, 'on');
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
expect(clientOn).toBeCalledTimes(13);
|
||||
});
|
||||
|
||||
test('Given No Events Found, Expect Successful Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(true);
|
||||
fs.readdirSync = jest.fn().mockReturnValue(["normal"]);
|
||||
|
||||
const client = {
|
||||
on: jest.fn(),
|
||||
} as unknown as Client;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadEvents(client);
|
||||
|
||||
const clientOn = jest.spyOn(client, 'on');
|
||||
|
||||
expect(result.valid).toBeTruthy();
|
||||
expect(clientOn).toBeCalledTimes(0);
|
||||
});
|
||||
|
||||
test('Given Event Folder Does Not Exist, Expect Failed Result', () => {
|
||||
process.env = {
|
||||
BOT_TOKEN: 'TOKEN',
|
||||
BOT_PREFIX: '!',
|
||||
FOLDERS_COMMANDS: 'commands',
|
||||
FOLDERS_EVENTS: 'events',
|
||||
}
|
||||
|
||||
process.cwd = jest.fn().mockReturnValue("../../tests/__mocks");
|
||||
fs.existsSync = jest.fn().mockReturnValue(false);
|
||||
fs.readdirSync = jest.fn().mockReturnValue(["normal.ts"]);
|
||||
|
||||
const client = {
|
||||
on: jest.fn(),
|
||||
} as unknown as Client;
|
||||
|
||||
const util = new Util();
|
||||
|
||||
const result = util.loadEvents(client);
|
||||
|
||||
expect(result.valid).toBeFalsy();
|
||||
expect(result.message).toBe("Event folder does not exist");
|
||||
});
|
||||
});
|
78
tsconfig.json
Normal file
78
tsconfig.json
Normal file
|
@ -0,0 +1,78 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
/* Visit https://aka.ms/tsconfig.json to read more about this file */
|
||||
|
||||
/* Basic Options */
|
||||
// "incremental": true, /* Enable incremental compilation */
|
||||
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */
|
||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
|
||||
// "lib": [], /* Specify library files to be included in the compilation. */
|
||||
// "allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
"declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
"sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "./dist", /* Redirect output structure to the directory. */
|
||||
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
|
||||
// "composite": true, /* Enable project compilation */
|
||||
// "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */
|
||||
// "removeComments": true, /* Do not emit comments to output. */
|
||||
// "noEmit": true, /* Do not emit outputs. */
|
||||
// "importHelpers": true, /* Import emit helpers from 'tslib'. */
|
||||
// "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
|
||||
// "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
|
||||
|
||||
/* Strict Type-Checking Options */
|
||||
"strict": true, /* Enable all strict type-checking options. */
|
||||
// "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */
|
||||
// "strictNullChecks": true, /* Enable strict null checks. */
|
||||
// "strictFunctionTypes": true, /* Enable strict checking of function types. */
|
||||
// "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
|
||||
// "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
|
||||
// "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
|
||||
// "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
|
||||
|
||||
/* Additional Checks */
|
||||
// "noUnusedLocals": true, /* Report errors on unused locals. */
|
||||
// "noUnusedParameters": true, /* Report errors on unused parameters. */
|
||||
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
|
||||
// "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */
|
||||
// "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */
|
||||
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */
|
||||
// "noPropertyAccessFromIndexSignature": true, /* Require undeclared properties from index signatures to use element accesses. */
|
||||
|
||||
/* Module Resolution Options */
|
||||
// "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
|
||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||
// "typeRoots": [], /* List of folders to include type definitions from. */
|
||||
// "types": [], /* Type declaration files to be included in compilation. */
|
||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
|
||||
|
||||
/* Source Map Options */
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
// "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
/* Advanced Options */
|
||||
"skipLibCheck": true, /* Skip type checking of declaration files. */
|
||||
"forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */
|
||||
},
|
||||
"include": [
|
||||
"./src",
|
||||
],
|
||||
"exclude": [
|
||||
"./tests"
|
||||
]
|
||||
}
|
Reference in a new issue