Compare commits

..

69 commits

Author SHA1 Message Date
523ec0a343 v2.0.3 2021-12-02 15:32:29 +00:00
6bc0cf3d6a
Update tests to match event changes 2021-12-02 15:32:09 +00:00
7861829f5d
Merge pull request #68 from Vylpes/bug/67-type-error
Fix issue where event files existing would crash the bot
2021-12-02 15:30:08 +00:00
c526423607
Fix issue where event files existing would crash the bot 2021-12-02 15:28:36 +00:00
6d030737fc
Bump version 2021-11-25 18:33:16 +00:00
acde8b0ccf
Add typings 2021-11-25 18:32:58 +00:00
7c85aec971 v2.0.1 2021-10-11 16:22:18 +01:00
8e9db75a30
Merge pull request #56 from Vylpes/dependabot/npm_and_yarn/tmpl-1.0.5
Bump tmpl from 1.0.4 to 1.0.5
2021-10-11 16:21:20 +01:00
5676efd969
Merge pull request #57 from Vylpes/dependabot/npm_and_yarn/ansi-regex-5.0.1
Bump ansi-regex from 5.0.0 to 5.0.1
2021-10-11 16:20:25 +01:00
16ac225a44 v2.0.0 2021-10-04 19:51:21 +01:00
dependabot[bot]
e302f2ee4d
Bump ansi-regex from 5.0.0 to 5.0.1
Bumps [ansi-regex](https://github.com/chalk/ansi-regex) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/chalk/ansi-regex/releases)
- [Commits](https://github.com/chalk/ansi-regex/compare/v5.0.0...v5.0.1)

---
updated-dependencies:
- dependency-name: ansi-regex
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 18:45:45 +00:00
dependabot[bot]
f6d57a1fda
Bump tmpl from 1.0.4 to 1.0.5
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

---
updated-dependencies:
- dependency-name: tmpl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-04 18:45:44 +00:00
c88a15187e
Merge pull request #55 from Vylpes/develop
v2.0
2021-10-04 19:45:15 +01:00
1a8baecfa1
Improvements 2021-10-04 19:43:53 +01:00
d3f9fc4fa0
Merge pull request #53 from Vylpes/feature/VBC-52
VBC-52 Use export default rather than class of the same name
2021-09-29 17:53:21 +01:00
5ce0960606
Remove useless async code 2021-09-29 17:52:21 +01:00
799b04e936
Update tests 2021-09-26 14:32:56 +01:00
3a9f1965ae
Update documentation 2021-09-26 14:13:09 +01:00
00a057792b
Make command loader use the default class 2021-09-26 14:12:21 +01:00
1b1933a9ce
Merge pull request #50 from Vylpes/feature/3-disable-commands
Feature/3 disable commands
2021-09-24 19:00:08 +01:00
b10ac37007
Update tests 2021-09-24 18:52:12 +01:00
3392e6f031
Add disabled command message reply 2021-09-24 18:46:49 +01:00
a3230cad20
Add tests 2021-09-22 19:59:40 +01:00
4e1c418246
Add ability to disable commands 2021-09-22 19:54:49 +01:00
Vylpes
10fe4501b5
Merge pull request #44 from Vylpes/feature/tests
Tests and CI
2021-08-21 16:00:28 +01:00
Ethan Lane
7e623b4b64 Update command names, add describe categories 2021-08-21 15:33:14 +01:00
Ethan Lane
bb848dcec3 Improvements 2021-08-21 15:20:40 +01:00
Ethan Lane
044140d58d Remove workflows 2021-08-20 16:13:02 +01:00
Ethan Lane
19e7539e53 Remove linting workflow 2021-08-20 16:10:06 +01:00
Ethan Lane
c3bcf76aac Add event mocks 2021-08-20 16:09:33 +01:00
Ethan Lane
8ee5c62481 Add github workflows 2021-08-20 16:06:59 +01:00
Ethan Lane
1b036609a9 Add ESLint 2021-08-20 15:58:41 +01:00
Ethan Lane
f11f3954a1 Improvements to Tests 2021-08-20 15:53:34 +01:00
Ethan Lane
338514ba1e Util tests, rewrite tests 2021-08-20 15:42:46 +01:00
Ethan Lane
2d2eaadea7 User role tests 2021-08-20 14:59:41 +01:00
Ethan Lane
569c22f1f4 More tests 2021-08-19 17:27:47 +01:00
Ethan Lane
1044c57e66 First util.ts test 2021-08-19 17:21:54 +01:00
Ethan Lane
a0a93a4737 Remove unused code 2021-08-18 21:27:44 +01:00
Ethan Lane
e6464d22cb Event tests 2021-08-18 21:11:49 +01:00
49d3d9c449
Add 2 more tests to events 2021-08-16 19:11:42 +01:00
da96bbefa5
Add start of event tests 2021-08-12 20:18:09 +01:00
Ethan Lane
99e375633b Add client tests 2021-07-30 15:49:12 +01:00
Vylpes
abe94ccc72
Merge pull request #42 from Vylpes/feature/ts
Feature/ts
2021-07-24 12:57:28 +01:00
Ethan Lane
a9400a95f2 Fix typo 2021-07-22 17:54:46 +01:00
Ethan Lane
8313e560b4 Set a response to false when it should be 2021-07-22 17:54:12 +01:00
Ethan Lane
9579ca837f Add ready event 2021-07-22 17:52:36 +01:00
Ethan Lane
a5123d6f79 Update documentation 2021-07-20 17:55:31 +01:00
Vylpes
e9112ee00e Fix events not working 2021-07-18 15:29:09 +01:00
Vylpes
6e700df0de Add CommandContext 2021-07-18 14:14:32 +01:00
Ethan Lane
23858f72fc Merge branch 'develop' into feature/ts 2021-07-16 17:25:40 +01:00
Ethan Lane
3100953f2e Clean up 2021-07-14 14:39:48 +01:00
Ethan Lane
29f80fba5c Rewrite in TypeScript 2021-07-14 13:55:36 +01:00
Ethan Lane
7870e35599 Swap to Yarn 2021-07-13 22:49:55 +01:00
Ethan Lane
33b05d9db6 Merge branch 'main' into develop 2021-07-03 18:26:38 +01:00
Ethan Lane
8e16f3a648 1.0.5 2021-06-26 21:39:02 +01:00
Vylpes
72030c625f
Merge pull request #35 from Vylpes/dependabot/npm_and_yarn/src/ws-7.5.0
Bump ws from 7.3.1 to 7.5.0 in /src
2021-06-21 19:53:30 +01:00
dependabot[bot]
fdfa5aebd1
Bump ws from 7.3.1 to 7.5.0 in /src
Bumps [ws](https://github.com/websockets/ws) from 7.3.1 to 7.5.0.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.3.1...7.5.0)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-21 18:52:48 +00:00
Vylpes
8af05a7fd8
Merge pull request #34 from Vylpes/dependabot/npm_and_yarn/ws-7.5.0
Bump ws from 7.3.1 to 7.5.0
2021-06-21 19:52:02 +01:00
dependabot[bot]
6bd6f0a3d5
Bump ws from 7.3.1 to 7.5.0
Bumps [ws](https://github.com/websockets/ws) from 7.3.1 to 7.5.0.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.3.1...7.5.0)

---
updated-dependencies:
- dependency-name: ws
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-16 20:42:11 +00:00
Ethan Lane
bec0e4871b Merge in dependabot/npm_and_yarn/ws-7.4.6 2021-06-10 09:14:32 +01:00
dependabot[bot]
1e578728c7
Bump ws from 7.3.1 to 7.4.6
Bumps [ws](https://github.com/websockets/ws) from 7.3.1 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.3.1...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-31 02:58:03 +00:00
Vylpes
b205826219
Update FUNDING.yml 2021-05-10 21:51:29 +01:00
Vylpes
6e38214df3
Update FUNDING.yml 2021-04-18 15:32:47 +01:00
Vylpes
86b8f3e351 Update default.md 2021-01-15 18:15:59 +00:00
Vylpes
e948540d80 Upload New File 2020-12-30 18:34:20 +00:00
Vylpes
02e3726692 Add new directory 2020-12-30 18:34:12 +00:00
Vylpes
6be00356c6 Add new directory 2020-12-30 18:34:01 +00:00
Vylpes
70ef646f39
Update FUNDING.yml 2020-11-03 18:08:19 +00:00
Vylpes
0351ed9d42
Update FUNDING.yml 2020-11-02 20:28:03 +00:00
53 changed files with 4620 additions and 5884 deletions

16
.env.template Normal file
View 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.

View file

@ -1 +1,2 @@
tests
node_modules
dist

View file

@ -1,44 +1,14 @@
{
"parserOptions": {
"ecmaVersion": 6
},
"root": true,
"parser": "@typescript-eslint/parser",
"plugins": [
"@typescript-eslint"
],
"extends": [
"eslint:recommended"
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/recommended"
],
"rules": {
"camelcase": "error",
"brace-style": [
"error",
"1tbs"
],
"comma-dangle": [
"error",
"never"
],
"comma-spacing": [
"error",
{
"before": false,
"after": true
}
],
"comma-style": [
"error",
"last"
],
"arrow-body-style": [
"error",
"as-needed"
],
"arrow-parens": [
"error",
"as-needed"
],
"arrow-spacing": "error",
"no-var": "error",
"prefer-template": "error",
"prefer-const": "error"
},
"globals": {
"exports": "writable",
"module": "writable",
@ -46,4 +16,4 @@
"process": "writable",
"console": "writable"
}
}
}

2
.github/FUNDING.yml vendored
View file

@ -1,6 +1,6 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
github: [vylpes]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: vylpes

10
.gitignore vendored
View file

@ -106,13 +106,13 @@ dist
# VylBot-Core Testing Files
commands/
events/
/bot.js
/config.json
/bot.ts
!tests/commands/
!tests/events/
!tests/__mocks/commands
!tests/__mocks/events
# Linux Environment Files
*.swp
cmdconfig.json
# macOS Environment Files
.DS_Store

View file

View file

@ -0,0 +1,29 @@
# Description
Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change.
Fixes # (issue)
## Type of change
Please delete options that are not relevant.
- Bug fix (non-breaking change which fixes an issue)
- New feature (non-breaking change which adds functionality)
- Breaking change (fix or feature that would cause existing functionality to not work as expected)
- This change requires a documentation update
# How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
# Checklist
- [ ] My code follows the style guidelines of this project
- [ ] I have performed a self-review of my own code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [ ] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] Any dependant changes have been merged and published in downstream modules

View file

@ -1,4 +1,4 @@
bot.js
config.json
.env
bot.ts
commands/
events/

View file

@ -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
getgravitysoftware@gmail.com.
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

View file

@ -12,7 +12,7 @@ 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 `getgravitysoftware@gmail.com`.
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).
@ -32,7 +32,7 @@ There are a few conventions that have developed over time for this project. When
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 [Gravity Software's Config Repo](https://github.com/GetGravitySoft/Config)
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**
@ -119,26 +119,26 @@ Enhancement suggestions are tracked as GitHub issues. After you've determined th
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.
* [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 `npm` you need network access.
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 `npm`
Install and build all of the dependencies using `yarn`
```bash
cd VylBot Core
npm install
cp config.json.template config.json
cd vylbot-core
yarn install
cp .env.template .env
```
And then use your text editor of choice to fill in the `config.json` file.
And then use your text editor of choice to fill in the `.env` file.
#### Build and Run
@ -147,15 +147,15 @@ If you want to understand how VylBot Core works or want to debug an issue, you'l
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
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
cd vylbot-core
git checkout master
git pull https://github.com/getgravitysoft/VylBot Core.git master
git pull https://github.com/vylpes/vylbot-core.git master
```
Manage any merge conflicts, commit them, and then push them to your fork.
@ -202,20 +202,18 @@ As well as eslint's recommended defaults.
Example
```js
function ban (member) {
let reason = "Example reason";
```ts
// hello.ts
import { Command, ICommandContext } from "vylbot-core";
let args = [
"one",
"two"
];
export class hello extends Command {
constructor() {
super();
}
member.ban(reason).then(() => {
// handle then here
}).catch(err => {
// handle error here
});
public override execute(context: ICommandContext) {
context.message.reply("Hello");
}
}
```
@ -251,7 +249,7 @@ There are a few conventions that have developed over time for this project. When
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 [Gravity Software's Config Repo](https://github.com/getgravitysoft/config)
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**

107
README.md
View file

@ -6,39 +6,104 @@ Discord bot client based upon Discord.js
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](https://gitlab.vylpes.com/Vylpes/vylbot-core/-/wikis/home) 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

View file

@ -1,3 +0,0 @@
{
}

View file

@ -1,3 +1,5 @@
/** @type {import('@ts-jest/dist/types').InitialOptionsTsJest} */
module.exports = {
testEnvironment: 'node'
}
preset: 'ts-jest',
testEnvironment: 'node',
};

4762
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,21 @@
{
"name": "vylbot-core",
"version": "20.0.0",
"version": "2.0.3",
"description": "A discord client based upon discord.js",
"main": "./src/index",
"main": "./dist/index",
"typings": "./dist",
"scripts": {
"test": "jest --coverage",
"build": "tsc",
"test": "jest",
"lint": "eslint .",
"lint:fix": "eslint . --fix"
"publish": "np"
},
"author": "Vylpes",
"license": "MIT",
"funding": "https://ko-fi.com/gravitysoftware",
"funding": "https://ko-fi.com/vylpes",
"dependencies": {
"discord.js": "^12.3.1",
"jest": "^26.6.3"
"dotenv": "^10.0.0"
},
"bugs": "https://github.com/vylpes/vylbot-core/issues",
"homepage": "https://github.com/vylpes/vylbot-core",
@ -24,6 +26,13 @@
],
"repository": "github:vylpes/vylbot-core",
"devDependencies": {
"eslint": "^7.17.0"
"@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"
}
}

View file

@ -1,64 +0,0 @@
// Required Components
const { Client } = require('discord.js');
const { validateConfig } = require('./validation');
const events = require('./events');
const util = require('./util');
// Required JSON
const expectedConfig = require('../json/expectedConfig.json');
// Client Class
class client extends Client {
constructor(config, commandConfig) {
// Call Discord.JS Client
super();
// Set the client's configuration, initialise events, initialise utilities
this.config = config;
this.commandConfig = commandConfig;
this.events = new events();
this.util = new util(this);
}
// Method to start the bot
start() {
// Check the bot is ready to start
if (!this._config) throw "Config has not been set";
if (!this._commandConfig) throw "Command Config has not been set";
// Events to handle commands
super.on("message", this.events.message);
super.on("ready", this.events.ready);
// Login to discord using Discord.JS
super.login(this._config.token);
// Load events
this.util.loadEvents();
}
// Config
get config() {
return this._config;
}
set config(config) {
// Validate the config
const val = validateConfig(config, expectedConfig);
if (!val.valid) throw val.message;
this._config = config;
}
// Command Config
get commandConfig() {
return this._commandConfig;
}
set commandConfig(config) {
this._commandConfig = config;
}
}
module.exports = client;

32
src/client/client.ts Normal file
View 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);
}
}

View file

@ -1,44 +0,0 @@
// Events Class
class event {
// Emit when a message is sent
// Used to check for commands
message(message) {
// Make sure command is sent within a guild and not by a bot, otherwise return and ignore
if (!message) return false;
if (!message.guild) return false;
if (message.author.bot) return false;
// Get the prefix from the config
const prefix = this.config.prefix;
// If the message starts with the prefix, then treat it as a command
if (message.content.substring(0, prefix.length).toLowerCase() == prefix.toLowerCase()) {
// Get the arguments in the message, after the first space (after the command name)
const args = message.content.substring(prefix.length).split(" ");
const name = args.shift();
// Load the command from the util class
const res = this.util.loadCommand(name, args, message);
if (!res.valid) {
if (res.message != 'File does not exist') throw res.message;
}
return {
"prefix": prefix,
"name": name,
"args": args,
"message": message
};
}
return false;
}
// Emit when bot is logged in and ready to use
ready() {
console.log("Ready");
}
}
module.exports = event;

75
src/client/events.ts Normal file
View 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");
}
}

View file

@ -1,123 +0,0 @@
// Required Components
const { readdirSync, existsSync } = require('fs');
function generateResponse(isValid, message) {
return {
"valid": isValid,
"message": message || "No message was given"
}
}
// Util Class
class util {
constructor(client) {
// Set the client
this._client = client;
}
// Load a command and send the arguments with it
loadCommand(name, args, message) {
// Get the current folder to check
const folder = this._client.config.commands;
// If the folder exists
if (existsSync(`${process.cwd()}/${folder}/`)) {
// If the file exists inside the folder
if (existsSync(`${process.cwd()}/${folder}/${name}.js`)) {
// Require the command file, now that we know it exists and initialise it
const commandFile = require(`${process.cwd()}/${folder}/${name}.js`);
const command = new commandFile();
// Require the command config file and get the config for the current command
const configJson = this._client.commandConfig;
const config = configJson[name];
// Get the list of required configurations the command needs
const commandConfigs = command.configs;
// Loop through all the required configs of the command
for (const i in commandConfigs) {
// If the command doesn't have the configs in the config string, throw an error
if (!config) return generateResponse(false, `${commandFile.name} requires ${commandConfigs[i]} in it's configuration`);
if (!config[commandConfigs[i]]) return generateResponse(false, `${commandFile.name} requires ${commandConfigs[i]} in it's configuration`);
}
// Get the roles required for this command to run
const requiredRoles = command.roles;
// Get the category, if there is no category, set it to a default string
if (!command.category) command.category = "none";
// Loop through all roles required
for (const i in requiredRoles) {
// If the user doesn't have a required role, don't run the command and let the user know
if (!message.member.roles.cache.find(role => role.name == requiredRoles[i])) {
message.reply(`You require the \`${requiredRoles[i]}\` role to run this command`);
return generateResponse(false, `You require the \`${requiredRoles[i]}\` role to run this command`);
}
}
// Get the ids of the users that are only permitted to run this command
const users = command.users;
// If the command has any limits, limit the command, otherwise default to anyone
if (users.length > 0) {
if (!users.includes(message.member.id)) {
message.reply(`You do not have permission to run this command`);
return generateResponse(false, "You do not have permission to run this command");
}
}
// Run the command and pass the command context with it
command[command.run]({
"command": name,
"arguments": args,
"client": this._client,
"message": message,
"config": config,
"commandConfigs": commandConfigs
});
return generateResponse(true, `loaded command '${name}' with arguments '${args}'`);
} else {
return generateResponse(false, 'File does not exist');
}
} else {
return generateResponse(false, 'Command folder does not exist');
}
}
// Load the events
loadEvents() {
// Get the current folder to check
const folder = this._client.config.events;
// If the folder exists
if (existsSync(`${process.cwd()}/${folder}/`)) {
// Get the files inside of this folder
const eventFiles = readdirSync(`${process.cwd()}/${folder}/`);
// Loop through all the files in the folder
for (let i = 0; i < eventFiles.length; i++) {
// Ignore non-javascript files
if (eventFiles[i].includes('.js')) {
// Get the event name, by taking the command file and removing the ".js" from the end
const eventName = eventFiles[i].split('.')[0];
// Get the file of the event
const file = require(`${process.cwd()}/${folder}/${eventName}.js`);
// Initialise the event class
const event = new file;
// Set the client to emit to this event
this._client.on(eventName, event[event.run]);
}
}
} else {
return generateResponse(false, 'Event folder does not exist');
}
}
}
module.exports = util;

131
src/client/util.ts Normal file
View 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",
}
}
}
}

View file

@ -1,33 +0,0 @@
function generateResponse(isValid, message) {
return {
"valid": isValid,
"message": message || "No message was given"
}
}
function validateConfig(config, expect) {
if (!config) return generateResponse(false, "Invalid config");
if (typeof config != "object") return generateResponse(false, "Invalid config");
if (!expect) return generateResponse(false, "Invalid expect");
if (typeof expect != "object") return generateResponse(false, "Invalid expect");
const keys = Object.keys(expect);
for (const i in keys) {
const e = expect[keys[i]];
if (!config[keys[i]])
return generateResponse(false, `'${keys[i]}' is not defined`);
if (typeof config[keys[i]] != e.type)
return generateResponse(false, `Invalid type of '${keys[i]}'. Was '${typeof config[keys[i]]}', Expected '${e.type}'`);
}
return generateResponse(true);
}
module.exports = {
generateResponse,
validateConfig
};

View file

@ -0,0 +1,4 @@
export interface IBaseResponse {
valid: boolean;
message?: string;
}

View file

@ -0,0 +1,7 @@
import { Message } from "discord.js";
export interface ICommandContext {
name: string;
args: string[];
message: Message;
}

View file

@ -1,5 +0,0 @@
module.exports = {
client: require('./client/client'),
command: require('./type/command'),
event: require('./type/event')
}

5
src/index.ts Normal file
View 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";

View file

@ -1,14 +0,0 @@
{
"token": {
"type": "string"
},
"prefix": {
"type": "string"
},
"commands": {
"type": "string"
},
"events": {
"type": "string"
}
}

View file

@ -1,75 +0,0 @@
class command {
constructor(run) {
this.run = run;
this._roles = [];
this._configs = [];
this._users = [];
}
// 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 configs() {
return this._configs;
}
set configs(conf) {
this._configs.push(conf);
}
get requiredConfigs() {
console.warn("'requiredConfigs' is deprecated and will be removed in a future version. Please use 'configs' instead.");
return this._configs;
}
set requiredConfigs(conf) {
console.warn("'requiredConfigs' is deprecated and will be removed in a future version. Please use 'configs' instead.");
this._configs.push(conf);
}
// Users
get users() {
return this._users;
}
set users(userid) {
this._users.push(userid);
}
}
module.exports = command;

16
src/type/command.ts Normal file
View 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) {
}
}

View file

@ -1,7 +0,0 @@
class event {
constructor(run) {
this.run = run;
}
}
module.exports = event;

55
src/type/event.ts Normal file
View 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() {
}
}

View file

@ -0,0 +1,7 @@
import { Command } from "../../../src/type/command";
export default class noCategory extends Command {
constructor() {
super();
}
}

View file

@ -0,0 +1,8 @@
import { Command } from "../../../src/type/command";
export default class normal extends Command {
constructor() {
super();
this._category = "General";
}
}

View file

@ -0,0 +1,8 @@
import { Command } from "../../../src/type/command";
export default class roles extends Command {
constructor() {
super();
this._roles = [ "Moderator" ];
}
}

View 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
View 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
View 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
View 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");
});
});

View file

@ -1,14 +0,0 @@
const { command } = require('../../src');
class test extends command {
constructor() {
super("test");
super.configs = "tester";
}
test(context) {
context.message.reply(`Testing done by ${context.config.tester}`);
}
}
module.exports = test;

View file

@ -1,14 +0,0 @@
const { command } = require('../../src');
class test extends command {
constructor() {
super("test");
super.roles = "Regular";
}
test(context) {
context.message.reply(`Testing done by ${context.config.tester}`);
}
}
module.exports = test;

View file

@ -1,14 +0,0 @@
const { command } = require('../../src');
class test extends command {
constructor() {
super("test");
super.users = "000000000000000001";
}
test(context) {
context.message.reply(`Testing done by ${context.config.tester}`);
}
}
module.exports = test;

View file

@ -1,5 +0,0 @@
{
"testing": {
"tester": "General Kenobi"
}
}

View file

@ -1,6 +0,0 @@
{
"token": "TOKEN",
"prefix": "d!",
"commands": "tests/commands",
"events": "tests/events"
}

View file

@ -1,14 +0,0 @@
{
"guild": "000000000000000000",
"author": {
"bot": false
},
"content": "d!testing param1",
"member": {
"roles": {
"cache": [
"NonRegular"
]
}
}
}

View file

@ -1,77 +0,0 @@
const { client } = require('../../../src');
const { readFileSync } = require('fs');
const { expect } = require('@jest/globals');
// Mocks
jest.mock('discord.js');
describe('Client Tests', () => {
let instance;
let config;
let commandConfig;
beforeEach(() => {
config = JSON.parse(readFileSync('tests/json/config.json'));
commandConfig = JSON.parse(readFileSync('tests/json/commandConfig.json'));
});
test('Configure Client (Correct paramaters)', () => {
instance = new client(config, commandConfig);
expect(instance.config).toBe(config);
expect(instance.commandConfig).toBe(commandConfig);
expect(instance.events).toBeDefined();
expect(instance.util).toBeDefined();
});
test('Configure Client (Undefined: config)', () => {
expect(() => {
instance = new client(config, commandConfig);
instance._config = undefined;
instance.start();
}).toThrow("Config has not been set");
});
test('Configure Client (Undefined: Command Config)', () => {
expect(() => {
instance = new client(config, commandConfig);
instance._commandConfig = undefined;
instance.start();
}).toThrow("Command Config has not been set");
});
test('Configure Client (Incorrect parameters: token)', () => {
expect(() => {
delete config.token;
instance = new client(config, commandConfig);
}).toThrow();
});
test('Configure Client (Incorrect parameters: prefix)', () => {
expect(() => {
delete config.prefix;
instance = new client(config, commandConfig);
}).toThrow();
});
test('Configure Client (Incorrect parameters: commands)', () => {
expect(() => {
delete config.commands;
instance = new client(config, commandConfig);
}).toThrow();
});
test('Configure Client (Incorrect parameters: events)', () => {
expect(() => {
delete config.events;
instance = new client(config, commandConfig);
}).toThrow();
});
test('Start Client', () => {
expect(() => {
instance = new client(config, commandConfig);
instance.start();
}).not.toThrow();
});
});

View file

@ -1,129 +0,0 @@
const events = require('../../../src/client/events');
const { readFileSync } = require('fs');
const { expect } = require('@jest/globals');
// Mocks
jest.mock('discord.js');
describe('events.message', () => {
let instance;
let message;
let config;
beforeEach(() => {
instance = new events();
message = JSON.parse(readFileSync('tests/json/message.json'));
config = JSON.parse(readFileSync('tests/json/config.json'));
instance.config = config;
instance.util = jest.fn();
instance.util.loadCommand = jest.fn(() => {
return {
"valid": true,
"message": "No message was set"
}
});
});
test('If no message should return', () => {
const res = instance.message();
expect(res).toBe(false);
});
test('If no guild should return', () => {
delete message.guild;
const res = instance.message(message);
expect(res).toBe(false);
});
test('If author is a bot should return', () => {
message.author.bot = true;
const res = instance.message(message);
expect(res).toBe(false);
});
test('Should loadCommand', () => {
const res = instance.message(message);
expect(instance.util.loadCommand).toHaveBeenCalledTimes(1);
expect(instance.util.loadCommand).toHaveBeenCalledWith('testing', ['param1'], message);
});
test('Should return correct values', () => {
const res = instance.message(message);
expect(res.prefix).toBe('d!');
expect(res.name).toBe('testing');
expect(res.args[0]).toBe('param1');
expect(res.message).toBe(message);
});
test('Should throw if response is invalid', () => {
instance.util.loadCommand = jest.fn(() => {
return {
"valid": false,
"message": "Invalid"
}
});
expect(() => {
instance.message(message)
}).toThrow('Invalid');
});
test('Should not throw if file does not exist', () => {
instance.util.loadCommand = jest.fn(() => {
return {
"valid": false,
"message": "File does not exist"
}
});
expect(() => {
instance.message(message)
}).not.toThrow();
});
test('Should return if message doesnt have prefix', () => {
message.content = "Just a normal message";
const res = instance.message(message);
expect(res).toBe(false);
});
});
describe('events.ready', () => {
let instance;
let message;
let config;
beforeEach(() => {
instance = new events();
message = JSON.parse(readFileSync('tests/json/message.json'));
config = JSON.parse(readFileSync('tests/json/config.json'));
instance.config = config;
instance.util = jest.fn();
instance.util.loadCommand = jest.fn(() => {
return {
"valid": true,
"message": "No message was set"
}
});
console = jest.fn();
console.log = jest.fn();
});
test('Should log when ready', () => {
const res = instance.ready();
expect(console.log).toHaveBeenCalledTimes(1);
expect(console.log).toHaveBeenCalledWith("Ready");
});
});

View file

@ -1,100 +0,0 @@
const util = require('../../../src/client/util');
const { readFileSync, read } = require('fs');
const { test, expect } = require('@jest/globals');
// Mocks
jest.mock('discord.js');
const fs = jest.createMockFromModule('fs');
fs.stat = jest.fn((path, cb) => {
cb(null);
});
describe('util.constructor', () => {
let instance;
let client;
beforeEach(() => {
client = jest.fn();
instance = new util(client);
});
test('Should set client', () => {
expect(instance._client).toBeDefined();
});
});
describe('util.loadCommand', () => {
let instance;
let message;
let client;
beforeEach(() => {
client = jest.fn();
client.config = JSON.parse(readFileSync('tests/json/config.json'));
client.commandConfig = JSON.parse(readFileSync('tests/json/commandConfig.json'));
instance = new util(client);
message = JSON.parse(readFileSync('tests/json/message.json'));
message.reply = jest.fn();
});
test('Should load command correctly', () => {
let res = instance.loadCommand('testing', 'param1', message);
expect(res.valid).toBe(true);
expect(res.message).toBe("loaded command 'testing' with arguments 'param1'");
});
test('Should load command correctly (no arguments)', () => {
let res = instance.loadCommand('testing', '', message);
expect(res.valid).toBe(true);
expect(res.message).toBe("loaded command 'testing' with arguments ''");
});
test('Should be invalid if it tries to load an undefined command', () => {
let res = instance.loadCommand('testingz', '', message);
expect(res.valid).toBe(false);
expect(res.message).toBe('File does not exist');
});
test('Should be invalid if incorrect configs', () => {
delete client.commandConfig.testing;
let res = instance.loadCommand('testing', 'param1', message);
expect(res.valid).toBe(false);
expect(res.message).toBe("test requires tester in it's configuration");
});
test('Should be invalid if incorrect configs (single config)', () => {
delete client.commandConfig.testing.tester;
let res = instance.loadCommand('testing', 'param1', message);
expect(res.valid).toBe(false);
expect(res.message).toBe("test requires tester in it's configuration");
});
test('Should throw error if command folder does not exist', () => {
client.config.commands = "falsefile";
let res = instance.loadCommand('testing', 'param1', message);
expect(res.valid).toBe(false);
expect(res.message).toBe('Command folder does not exist');
});
test('Should throw error if user does not have required role', () => {
let res = instance.loadCommand('testingRoles', 'param1', message);
expect(res.valid).toBe(false);
expect(res.message).toBe('You require the `Regular` role to run this command');
});
test('Should throw error if user is not in users array', () => {
let res = instance.loadCommand('testingUsers', 'param1', message);
expect(res.valid).toBe(false);
expect(res.message).toBe('You do not have permission to run this command');
})
});

View file

@ -1,72 +0,0 @@
const { generateResponse, validateConfig } = require('../../../src/client/validation');
const { readFileSync } = require('fs');
describe('Validation: generateResponse', () => {
test('Returns the corect response', () => {
const isValidWithMessage = generateResponse(true, "Test Message");
const isValidNoMessage = generateResponse(true);
const notValidWithMessage = generateResponse(false, "Test Message");
const notValidNoMessage = generateResponse(false);
expect(isValidWithMessage.valid).toBe(true);
expect(isValidWithMessage.message).toBe('Test Message');
expect(isValidNoMessage.valid).toBe(true);
expect(isValidNoMessage.message).toBe('No message was given');
expect(notValidWithMessage.valid).toBe(false);
expect(notValidWithMessage.message).toBe('Test Message');
expect(notValidNoMessage.valid).toBe(false);
expect(notValidNoMessage.message).toBe('No message was given');
});
});
describe('Validation: validateConfig', () => {
let config;
let expected;
beforeEach(() => {
config = JSON.parse(readFileSync('tests/json/config.json'));
expected = JSON.parse(readFileSync('src/json/expectedConfig.json'));
});
test('Validates expected config as valid', () => {
const res = validateConfig(config, expected);
expect(res.valid).toBe(true);
expect(res.message).toBe('No message was given');
});
test('Validates unexpected config as invalid (token)', () => {
delete config.token;
const res = validateConfig(config, expected);
expect(res.valid).toBe(false);
expect(res.message).toBe("'token' is not defined");
});
test('Validates unexpected config as invalid (prefix)', () => {
delete config.prefix;
const res = validateConfig(config, expected);
expect(res.valid).toBe(false);
expect(res.message).toBe("'prefix' is not defined");
});
test('Validates unexpected config as invalid (commands)', () => {
delete config.commands;
const res = validateConfig(config, expected);
expect(res.valid).toBe(false);
expect(res.message).toBe("'commands' is not defined");
});
test('Validates unexpected config as invalid (events)', () => {
delete config.events;
const res = validateConfig(config, expected);
expect(res.valid).toBe(false);
expect(res.message).toBe("'events' is not defined");
});
});

View file

@ -1,190 +0,0 @@
const command = require('../../../src/type/command');
describe('Command: constructor', () => {
let instance;
beforeEach(() => {
instance = new command("test");
});
test('Command run is set correctly', () => {
expect(instance.run).toBe("test");
});
test('Command roles is set correctly', () => {
expect(typeof instance._roles).toBe('object');
expect(instance._roles.length).toBe(0);
});
test('Command configs is set correctly', () => {
expect(typeof instance._configs).toBe('object');
expect(instance._configs.length).toBe(0);
});
test('Command users is set correctly', () => {
expect(typeof instance._users).toBe('object');
expect(instance._users.length).toBe(0);
});
});
describe('Command: description', () => {
let instance;
beforeEach(() => {
instance = new command("test");
});
test('Setting description', () => {
instance.description = "desc";
expect(instance._description).toBe("desc");
});
test('Getting description', () => {
instance.description = "desc";
expect(instance.description).toBe("desc");
});
});
describe('Command: category', () => {
let instance;
beforeEach(() => {
instance = new command("test");
});
test('Setting category', () => {
instance.category = "cat";
expect(instance._category).toBe("cat");
});
test('Getting category', () => {
instance.category = "cat";
expect(instance.category).toBe("cat");
});
});
describe('Command: usage', () => {
let instance;
beforeEach(() => {
instance = new command("test");
});
test('Setting usage', () => {
instance.usage = "use";
expect(instance._usage).toBe("use");
});
test('Getting usage', () => {
instance.usage = "use";
expect(instance.usage).toBe("use");
});
});
describe('Command: roles', () => {
let instance;
beforeEach(() => {
instance = new command("test");
});
test('Setting roles (1 role)', () => {
instance.roles = "role0";
expect(instance._roles.length).toBe(1);
expect(instance._roles[0]).toBe("role0");
});
test('Getting roles (1 role)', () => {
instance.roles = "role0";
expect(instance.roles.length).toBe(1);
expect(instance.roles[0]).toBe("role0");
});
test('Setting roles (2 roles)', () => {
instance.roles = "role0";
instance.roles = "role1";
expect(instance._roles.length).toBe(2);
expect(instance._roles[0]).toBe("role0");
expect(instance._roles[1]).toBe("role1");
});
test('Getting roles (2 roles)', () => {
instance.roles = "role0";
instance.roles = "role1";
expect(instance.roles.length).toBe(2);
expect(instance.roles[0]).toBe("role0");
expect(instance.roles[1]).toBe("role1");
});
});
describe('Command: configs', () => {
let instance;
beforeEach(() => {
instance = new command("test");
});
test('Setting configs (1 config)', () => {
instance.configs = "config0";
expect(instance._configs.length).toBe(1);
expect(instance._configs[0]).toBe("config0");
});
test('Getting configs (1 config)', () => {
instance.configs = "config0";
expect(instance.configs.length).toBe(1);
expect(instance.configs[0]).toBe("config0");
});
test('Setting configs (2 configs)', () => {
instance.configs = "config0";
instance.configs = "config1";
expect(instance._configs.length).toBe(2);
expect(instance._configs[0]).toBe("config0");
expect(instance._configs[1]).toBe("config1");
});
test('Getting configs (2 configs)', () => {
instance.configs = "config0";
instance.configs = "config1";
expect(instance.configs.length).toBe(2);
expect(instance.configs[0]).toBe("config0");
expect(instance.configs[1]).toBe("config1");
});
});
describe('Command: users', () => {
let instance;
beforeEach(() => {
instance = new command("test");
});
test('Setting users (1 user)', () => {
instance.users = "user0";
expect(instance._users.length).toBe(1);
expect(instance._users[0]).toBe("user0");
});
test('Getting users (1 user)', () => {
instance.users = "user0";
expect(instance.users.length).toBe(1);
expect(instance.users[0]).toBe("user0");
});
test('Setting users (2 user)', () => {
instance.users = "user0";
instance.users = "user1";
expect(instance._users.length).toBe(2);
expect(instance._users[0]).toBe("user0");
expect(instance._users[1]).toBe("user1");
});
test('Getting users (2 users)', () => {
instance.users = "user0";
instance.users = "user1";
expect(instance.users.length).toBe(2);
expect(instance.users[0]).toBe("user0");
expect(instance.users[1]).toBe("user1");
});
});

View file

@ -1,13 +0,0 @@
const event = require('../../../src/type/event');
describe('Event: constructor', () => {
let instance;
beforeEach(() => {
instance = new event("test");
});
test('Event run is set correctly', () => {
expect(instance.run).toBe("test");
});
});

78
tsconfig.json Normal file
View 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"
]
}

3248
yarn.lock Normal file

File diff suppressed because it is too large Load diff