Began revising documentation and copied changelog

This commit is contained in:
WatDuhHekBro 2021-04-06 08:19:41 -05:00
parent cd9aaa5f4b
commit 7284342514
11 changed files with 400 additions and 284 deletions

View File

@ -10,6 +10,7 @@ LICENSE
dist/
data/
docs/
*.md
tmp/
test*
!test/

109
CHANGELOG.md Normal file
View File

@ -0,0 +1,109 @@
# 2.8.4 - Reworked the react command
- `react` is now a fully versatile command for helping you react to other messages with non-server emotes.
- Now properly reacts to the previous message (bug fix).
- Provides you the option to react to any number of messages before your message (3 messages above yours for example).
- Renamed guild ID to message ID for clarity's sake.
- Now removes the bot's own reaction after a few seconds to make the reaction count more accurate.
- Now lets you react with multiple messages in a row.
- Now reacts with ❓ if no reactions were found at all (see below).
- `emote`:
- Is now case-sensitive again (because there are too many name conflicts).
- Accepts multiple emotes for tiled emotes.
- Now reacts to your message with ❓ instead of `None of those emote names were valid!` so that the bot doesn't spam the chat if you can't find the right emote (because you'll still be able to delete your messages).
- `thonk` now stores the last specified phrase so you can repeat a phrase with different diacritics.
# 2.8.3 - The ultimate meme
# 2.8.2
- Added a changelog.
- Added an extra instruction to the readme's installation.
- Made commands utilize the existing `Array.random()` function.
- Removed concatenation when using template strings.
- Added `Number.pluralise()` for convenient pluralization.
- Reworked the `neko` command.
- Made `whoami` sync up with `whois` by using the same config.
- Fixed a bug with `emote` where it wouldn't find any upper case emotes and made it more lenient to just include any emote (so you don't have to remember the exact emote name).
- Moved lists and gathering shop items outside of `exports.run()` so that it initializes once during the bot's initialization (or when reloaded) rather than every time the command is called.
# 2.8.1 - Modularized eco shop and eco buy
- Fixed scanemotes sometimes not displaying all emotes. This was an issue of not accounting for whether an emote was animated or not.
- Modularized `eco shop` and `eco buy`. Shop items are now in the `shop` subfolder and `eco shop` now separates every 5 shop items into separate pages automatically.
# 2.8.0 - Added graphical welcome setting
- Adds a new option to the `set` and `conf` commands, allowing you to enable an image being sent as a welcome.
# 2.7.1 - Added eco buy laser bridge and reworked scanemotes
- `eco buy laser bridge` - Added a shop item. Buy what is technically a laser bridge. Costs 3 Mons.
- `insult` - Now pings the user who activated it.
- `scanemotes` - Reworked the command after a test run in a big server.
- Merged the unsorted and sorted emote listings into one section. The unsorted emotes pretty much had a random order as it was pretty much which emote was added first as the search went on, so nothing's gone there. `#1 :emote: x 20 - 30.532% (Bots: 132)`
- Bumped the cooldown from 1 hour to 1 day.
- An updated progress meter which now stays on a single channel at a time because it's no longer asynchronous. This progress bar also works with Discord's rate limits. `Searching channel ___... (___ messages scanned, x/y channels scanned)`
- Now includes all emotes in a server, even if they haven't been used.
- Now properly counts emote usage for reactions (whether or not a bot reacted to a message)
# 2.7.0 - Added percentages to scanemotes
## Major Changes
- Added an hour long cooldown to `scanemotes` per server because it's a very memory-intensive task to search through every single message.
- Added a second list of emotes to `scanemotes`, sorting by percentage of users-only usage.
- Added a function to the client's common functions to generate a page users can turn.
## Minor Changes
- `avatar`
- Now has proper error handling when searching by mention and ID.
- No longer pings the user, it just sends the image link by itself.
- `eco`
- Merges `sender.id + message.guild.id` into `compositeID` since it's so frequently used.
- Bug Fix: If you have exactly 1 Mon and you pay someone 1 Mon, they'll get 1 more Mon and you'll still have 1 Mon because the 0 coerces to false resetting your money, because JS soft comparison. Fixed by using the "in" operator instead.
- Uses else ifs to make the command marginally faster.
- Now properly handles mentions and extracting the user ID from them in the `pay` subcommand.
- Added a message that occurs when the user tries to buy an item that doesn't exist.
- Added an `insult` command which will have the bot type out the navy seals copypasta for a minute.
- Modified the `invite` command to auto-generate a link based on the current bot client ID rather than having it be hardcoded to TravBot specifically.
- Added error checking to `scanemotes` so users aren't left in the dark if something happens.
- On big servers, `scanemotes` should now have emotes actually show up.
# 2.6.1 - Hotfix: Scan emotes no longer requires admin
- Fixed the `scanemotes` command to no longer require admin permissions. This was due to an oversight: There can be channels which the bot doesn't have access to, ie private channels. You have to check if the bot has access to a channel because the filter will gather all text-based channels regardless. Admin permissions overrides all restrictions, which is why it only worked with admin permissions.
- Entering a username in the `avatar` command unsuccessfully will now send a message in chat.
# 2.6.0 - Added the ability to get other users' avatars and see emote usage
- You can now scan the current guild for emote usage, collecting all emotes used in messages and reactions. (example below)
![2020-06-19 04_08_22-Window](https://user-images.githubusercontent.com/44940783/85116219-98a69280-b1e2-11ea-9246-b8f5ff2537ea.png)
- You can now get other avatars by providing an ID (works even when the bot doesn't share the same server as that user), username, or by pinging them.
- Included the fix for `serverinfo`.
# 2.5.3
- Changed default prefix for setup.
- Enhanced `react` command. New optional guildID arg.
- Added message logger.
- Fixed calc permission error.
- Removed `delete` command.
- Added ignored and notified channels to logger.
- Added images to logger. Added author to logger.
- Emote command is now not case-sensitive.
# 2.5.2 - Bug fixes to the "eco" command
- Now prevents users from sending negative amounts of money to others (minimum of 1 Mon).
- Also prevents users from sending decimal amounts.
- Fixes a potentially wrong substring for user IDs.
- Now requires an argument when using the "desc" command.
# 2.5.1
- Added shop functionality to eco.
- Fixed faulty guild check.
- Attempt at fixing emote for eco cute.
- Pluralised "mon" for eco handhold.
- Added `translate` command.
# 2.5.0 - Added the "pay" sub-command to "eco"
# 2.4.1
- Added Procfile.
- Updated whoami's keys.
- Rewrote `desc` command.
# 2.4.0 - Implemented music system
- VC Rename command
- Travis CI configuration
- Music system
- Dependency updates

View File

@ -1,6 +1,24 @@
# TravBot-v3
Fourth revision of TravBot, version number 3.0.0.
<p align="center">
<img src="https://i.imgur.com/l2E2Tfi.png"/>
</p>
<p align="center">
<a href="https://choosealicense.com/licenses/mit/">
<img src="https://img.shields.io/github/license/keanuplayz/travbot-v3" alt="License">
</a>
<a href="https://github.com/keanuplayz/TravBot-v3/blob/master/CHANGELOG.md">
<img src="https://img.shields.io/github/package-json/v/keanuplayz/travbot-v3" alt="Version">
</a>
<a href="https://github.com/keanuplayz/TravBot-v3/blob/typescript/CHANGELOG.md">
<img src="https://img.shields.io/github/package-json/v/keanuplayz/travbot-v3/typescript" alt="Version (Dev)">
</a>
<a href="https://discord.js.org/">
<img src="https://img.shields.io/github/package-json/dependency-version/keanuplayz/travbot-v3/discord.js" alt="Discord.js Version">
</a>
</p>
Fourth revision of [TravBot](https://github.com/keanuplayz/TravBot), version number 3.0.0.
This is the repo belonging to the code of TravBot v3.
@ -8,14 +26,19 @@ This version will be the final revision of TravBot, this being the final structu
Thank you for coming on this journey with me, but it is time to put the big changes to an end.
## Installation
1. `npm install`
2. `npm run build`
3. `npm start`
## Contributing
To get information on how to contribute to this project, see the [overview](docs/Overview.md) as well as other files in the `docs` folder meant for developers.
## Special Thanks
Special thanks to:
- Lexi Sother (TravBot v2, structural overhaul. Reviewing PRs.)
- WatDuhHekBro (a _lot_ of contributions to TravBot v2)
- Zeehondie (Ideas for various commands.)
### License
Refer to the [LICENSE](https://github.com/keanuplayz/TravBot-v3/tree/master/LICENSE) file.
- Lexi Sother (TravBot v2, structural overhaul. Reviewing PRs.)
- WatDuhHekBro (a *lot* of contributions to TravBot v2)
- Zeehondie (Ideas for various commands.)

View File

1
docs/DesignDecisions.md Normal file
View File

@ -0,0 +1 @@
Coming Soon™

View File

@ -1,199 +1,19 @@
# What this is
# Table of Contents
This is a user-friendly version of the project's structure (compared to the amalgamation that has become [specifications](Specifications.md) which is just a list of design decisions and isn't actually helpful at all for understanding the code). This will follow the line of logic that the program would run through.
# Building/Setup
- `npm run dev` runs the TypeScript compiler in watch mode, meaning that any changes you make to the code will automatically reload the bot.
- This will take all the files in `src` (where all the code is) and compile it into `dist` which is what the program actually uses.
- If there's a runtime error, `dist\commands\test.js:25:30` for example, then you have to into `dist` instead of `src`, then find the line that corresponds.
# Launching
When you start the program, it'll run the code in `index` (meaning both `src/index.ts` and `dist/index.js`, they're the same except that `dist/<...>.js` is compiled). The code in `index` will call `setup` and check if `data/config.json` exists, prompting you if it doesn't. It'll then run initialization code.
...
# Structure
- `commands` contains all the commands.
- `defs` contains static definitions.
- `core` contains the foundation of the program. You won't need to worry about this unless you're modifying pre-existing behavior of the `Command` class for example or add a function to the library.
- `events` contains all the events. Again, you generally won't need to touch this unless you're listening for a new Discord event.
- `src`: Contains all the code for the bot itself. Code directly in this folder is for the starting index file as well as commonly accessed utility files.
- `core`: This is currently where the command handler is. Try to keep it as isolated as possible, it might split off to become its own module.
- `commands`: Where all the dynamically loaded commands are stored. You can use a subfolder to specify the command category. Specify a `modules` folder to create files that are ignored by the command loader.
- `modules`: This is where mostly single-purpose blocks of code go. (This is **not** the same as a `modules` folder under `commands`.)
- `defs`: Contains static definitions.
- `dist`: This is where the runnable code in `src` compiles to. (The directory structure mirrors `src`.)
- `data`: Holds all the dynamic/private data used by the bot. This folder is not meant to hold definitions.
- `docs`: Information for developers who want to contribute.
# The Command Class
A valid command file must be located in `commands` and export a default `Command` instance. Assume that we're working with `commands/money.ts`.
```js
import Command from '../core/command';
export default new Command({
//...
});
```
The `run` property can be either a function or a string. If it's a function, you get one parameter, `$` which represents the common library (see below). If it's a string, it's a variable string.
- `%author%` pings the person who sent the message.
- `%prefix%` gets the bot's current prefix in the selected server.
```js
import Command from '../core/command';
import { CommonLibrary } from '../core/lib';
export default new Command({
run: '%author%, make sure to use the prefix! (%prefix)',
});
```
...is equal to...
```js
import Command from '../core/command';
import { CommonLibrary } from '../core/lib';
import { getPrefix } from '../core/structures';
export default new Command({
async run($: CommonLibrary): Promise<any> {
$.channel.send(
`${$.author.toString()}, make sure to use the prefix! (${getPrefix(
$.guild,
)})`,
);
},
});
```
Now here's where it gets fun. The `Command` class is a recursive structure, containing other `Command` instances as properties.
- `subcommands` is used for specific keywords for accessing a certain command. For example, `$eco pay` has a subcommand of `pay`.
```js
import Command from '../core/command';
import { CommonLibrary } from '../core/lib';
export default new Command({
subcommands: {
pay: new Command({
//...
}),
},
});
```
There's also `user` which listens for a ping or a Discord ID, `<@237359961842253835>` and `237359961842253835` respectively. The argument will be a `User` object.
```js
import Command from '../core/command';
import { CommonLibrary } from '../core/lib';
export default new Command({
user: new Command({
async run($: CommonLibrary): Promise<any> {
$.debug($.args[0].username); // "WatDuhHekBro"
},
}),
});
```
There's also `number` which checks for any number type except `Infinity`, converting the argument to a `number` type.
```js
import Command from '../core/command';
import { CommonLibrary } from '../core/lib';
export default new Command({
number: new Command({
async run($: CommonLibrary): Promise<any> {
$.debug($.args[0] + 5);
},
}),
});
```
And then there's `any` which catches everything else that doesn't fall into the above categories. The argument will be a `string`.
```js
import Command from '../core/command';
import { CommonLibrary } from '../core/lib';
export default new Command({
any: new Command({
async run($: CommonLibrary): Promise<any> {
$.debug($.args[0].toUpperCase());
},
}),
});
```
Of course, maybe you just want to get string arguments regardless, and since everything is an optional property, so you'd then just include `any` and not `subcommands`, `user`, or `number`.
## Other Properties
- `description`: The description for that specific command.
- `endpoint`: A `boolean` determining whether or not to prevent any further arguments. For example, you could prevent `$money daily too many arguments`.
- `usage`: Provide a custom usage for the help menu. Do note that this is relative to the subcommand, so the below will result in `$money pay <user> <amount>`.
```js
import Command from '../core/command';
import { CommonLibrary } from '../core/lib';
export default new Command({
subcommands: {
pay: new Command({
usage: '<user> <amount>',
}),
},
});
```
- `permission`: The permission to restrict the current command to. You can specify it for certain subcommands, useful for having `$money` be open to anyone but not `$money admin`. If it's `null` (default), the permission will inherit whatever was declared before (if any). The default value is NOT the same as `Command.PERMISSIONS.NONE`.
- `aliases`: A list of aliases (if any).
## Alternatives to Nesting
For a lot of the metadata properties like `description`, you must provide them when creating a new `Command` instance. However, you can freely modify and attach subcommands, useful for splitting a command into multiple files.
```js
import pay from "./subcommands/pay";
const cmd = new Command({
description: "Handle your money."
});
cmd.subcommands.set("pay", pay);
cmd.run = async($: CommonLibrary): Promise<any> {
$.debug($.args);
};
cmd.any = new Command({
//...
});
export default cmd;
```
## Error Handling
Any errors caused when using `await` or just regular synchronous functions will be automatically caught, you don't need to worry about those. However, promises must be caught manually. For example, `$.channel.send("")` will throw an error because you can't send empty messages to Discord, but since it's a promise, it'll just fade without throwing an error. There are two ways to do this:
- `$.channel.send("").catch($.handler.bind($))`
- `$.channel.send("").catch(error => $.handler(error))`
# The Common Library
This is the container of functions available without having to import `core/lib`, usually as `$`. When accessing this from a command's `run` function, it'll also come with shortcuts to other properties.
## Custom Wrappers
- `$(5)` = `new NumberWrapper(5)`
- `$("text")` = `new StringWrapper("text")`
- `$([1,2,3])` = `new ArrayWrapper([1,2,3])`
## Custom Logger
- `$.log(...)`
- `$.warn(...)`
- `$.error(...)`
- `$.debug(...)`
- `$.ready(...)` (only meant to be used once at the start of the program)
# Cleanup is Soon™
## Convenience Functions

View File

@ -1,20 +0,0 @@
# Getting Started
1. `npm install`
2. `npm run build`
3. `npm start`
# Getting Started (Developers)
1. `npm install`
2. `npm run dev`
3. Familiarize yourself with the [project's structure](Documentation.md).
4. Make sure to avoid using `npm run build`! This will remove all your dev dependencies (in order to reduce space used). Instead, use `npm run once` to compile and build in non-dev mode.
5. Begin developing.
## Don't forget to...
- ...update the [changelog](CHANGELOG.md) and any other necessary docs.
- ...update the version numbers in `package.json` and `package-lock.json`.
- ...make sure the test suite passes by running `npm test`.
- ...format the code by running `npm run format`.

230
docs/Overview.md Normal file
View File

@ -0,0 +1,230 @@
# Table of Contents
- [Introduction](#introduction)
- [Setting up the development environment](#setting-up-the-development-environment)
- [Adding a new command](#adding-a-new-command)
- [Adding a new non-command feature](#adding-a-new-non-command-feature)
# Introduction
This is a brief overview that'll describe where and how to add new features to TravBot. For more details on specific functions, head over to the [documentation](Documentation.md). Assume the prefix for all of these examples is `$`.
# Setting up the development environment
1. `npm install`
2. `npm run dev` *(runs the TypeScript compiler in watch mode, meaning any changes you make to the code will automatically reload the bot)*
*Note: Make sure to avoid using `npm run build`! This will remove all your dev dependencies (in order to reduce space used). Instead, use `npm run once` to compile and build in non-dev mode.*
## Don't forget to...
- ...update the [changelog](../CHANGELOG.md) and any other necessary docs.
- ...update the version numbers in [package.json](../package.json) and [package-lock.json](../package-lock.json).
# Adding a new command
To add a new command, go to `src/commands` and either copy the [template](../src/commands/template.ts) or rename the auto-generated test file (`../src/commands/test.ts`). For reference, this is the barebones requirement for a command file.
## The very basics of a command
```ts
import {NamedCommand} from "../core";
export default new NamedCommand();
```
To make something actually happen when the command is run however, you implement the `run` property.
```ts
import {Command, NamedCommand} from "../core";
export default new NamedCommand({
async run({message, channel, guild, author, member, client, args}) {
channel.send("test");
}
});
```
### Quick note on the run property
You can also enter a string for the `run` property which will send a message with that string specified ([you can also specify some variables in that string](Documentation.md#)). The above is functionally equivalent to the below.
```ts
import {Command, NamedCommand} from "../core";
export default new NamedCommand({
run: "test"
});
```
## Introducing subcommands
Where this command handler really shines though is from its subcommands feature. You can filter and parse argument lists in a declarative manner.
```ts
import {Command, NamedCommand} from "../core";
export default new NamedCommand({
user: new Command({
async run({message, channel, guild, author, member, client, args}) {
const user = args[0];
}
})
});
```
Here, . For example, if this file was named `test.ts`, `$test <@237359961842253835>` would get the user by the ID `237359961842253835` into `args[0]` as a [User](https://discord.js.org/#/docs/main/stable/class/User) object. `$test experiment` would run as if you just called `$test` *(given that [endpoint](Documentation.md#) isn't set to `true`)*.
If you want, you can typecast the argument to be more strongly typed, because the type of `args` is `any[]`. *([See why if you're curious.](DesignDecisions.md#))*
```ts
import {Command, NamedCommand} from "../core";
import {User} from "discord.js";
export default new NamedCommand({
user: new Command({
async run({message, channel, guild, author, member, client, args}) {
const user = args[0] as User;
}
})
});
```
## Keyed subcommands
For keyed subcommands, you would instead use a `NamedCommand`.
```ts
import {Command, NamedCommand} from "../core";
export default new NamedCommand({
run: "one",
subcommands: {
bread: new NamedCommand({
run: "two"
})
}
});
```
If the file was named `cat.ts`:
- `$cat` would output `one`
- `$cat bread` would output `two`
Only `bread` in this case would lead to `two` being the output, which is different from the generic subcommand types in previous examples.
You get an additional property with `NamedCommand`s: `aliases`. That means you can define aliases not only for top-level commands, but also every layer of subcommands.
```ts
import {Command, NamedCommand} from "../core";
export default new NamedCommand({
aliases: ["potato"],
subcommands: {
slice: new NamedCommand({
aliases: ["pear"]
})
}
});
```
For example, if this file was named `plant.ts`, the following would work:
- `$plant`
- `$potato`
- `$plant slice`
- `$plant pear`
- `$potato slice`
- `$potato pear`
## Metadata / Command Properties
You can also specify metadata for commands by adding additional properties. Some of these properties are per-command while others are inherited.
```ts
import {Command, NamedCommand} from "../core";
export default new NamedCommand({
description: "desc one",
subcommands: {
pineapple: new NamedCommand({
//...
})
}
});
```
`description` is an example of a per-command property (which is used in a help command). If the file was named `siege.ts`:
- The description of `$siege` would be `desc one`.
- There wouldn't be a description for `$siege pineapple`.
This is in contrast to inherited properties.
```ts
import {Command, NamedCommand, CHANNEL_TYPE} from "../core";
export default new NamedCommand({
channelType: CHANNEL_TYPE.GUILD,
subcommands: {
pineapple: new NamedCommand({
//...
})
}
});
```
Here, the property `channelType` would spread to all subcommands unless a subcommand defines it. Using the above example, the `channelType` for both `$siege` and `$siege pineapple` would be `CHANNEL_TYPE.GUILD`.
*To get a full list of metadata properties, see the [documentation](Documentation.md#).*
## Utility Functions
You'll have to import these manually, however it's in the same import list as `Command` and `NamedCommand`.
```ts
import {Command, NamedCommand, paginate} from "../core";
export default new NamedCommand({
async run({message, channel, guild, author, member, client, args}) {
paginate(/* enter your code here */);
}
});
```
*To get a full list of utility functions, see the [documentation](Documentation.md#).*
# Adding a new non-command feature
If the feature you want to add isn't specifically a command, or the change you're making involves adding event listeners, go to `src/modules` and create a file. Code written here won't be automatically loaded, so make sure to open [src/index.ts](../src/index.ts) and add an import statement at the bottom.
```ts
import "./modules/myModule";
```
This will just run whatever code is in there.
## Listening for events
Rather than have an `events` folder which contains dynamically loaded events, you add an event listener directly via `client.on("...", () => {})`. *([See why if you're curious.](DesignDecisions.md#))* The client can be imported from the index file.
```ts
import {client} from "..";
client.on("message", (message) => {
//...
});
```
As long as you make sure to add that import statement in the index file itself, the event(s) will load.
**Just make sure you instantiate the client *before* you import a module or you'll get a runtime error.**
`index.ts`
```ts
import {Client} from "discord.js";
export const client = new Client();
//...
import "./modules/myModule";
```

View File

@ -1,48 +0,0 @@
# Structure
The top-level directory is reserved for files that have to be there for it to work as well as configuration files.
- `src`: Contains all the code for the bot itself. Code in this directory is for independent tasks keeping the initialization out of the subdirectories.
- `core`: This is where core structures and critical functions for the bot go.
- `modules`: This is where modules go that accomplish one specific purpose but isn't so necessary for the bot to function. The goal is to be able to safely remove these without too much trouble.
- `commands`: Here's the place to store commands. The file name determines the command name.
- `subcommands/`: All commands here are ignored by the category loader. Here is where you can split commands into different files. Also works per directory, for example, `utility/subcommands/` is ignored.
- `<directory>/`: Specify a directory which'll group commands into a category. For example, a `utility` folder would make all commands inside have the `Utility` category.
- `<file>.ts`: All commands at this level will have the `Miscellaneous` category.
- `events`: Here's the place to store events. The file name determines the event type.
- `dist`: This is where the runnable code in `src` compiles to. (The directory structure mirrors `src`.)
- `test`: Used for all the unit tests.
- `data`: Holds all the dynamic data used by the bot. This is what you modify if you want to change stuff for just your instance of the bot.
- `standard`: Contains all the standard data to be used with the project itself. It's part of the code and will not be checked for inaccuracies because it's not meant to be easily modified.
- `docs`: Used for information about the design of the project.
# Specific Files
This list starts from `src`/`dist`.
- `index`: This is the entry point of the bot. Here is where all the initialization is done, because the idea is to keep repeatable code in separate modules while having code that runs only once here designating this is **the** starting point.
- `setup`: Used for the first time the bot is loaded, walking the user through setting up the bot.
- `core/lib`: Exports a function object which lets you wrap values letting you call special functions as well as calling utility functions common to all commands.
- `core/structures`: Contains all the structures that the dynamic data read from JSON files should follow. This exports instances of these classes.
- `core/command`: Contains the class used to instantiate commands.
- `core/event`: Contains the class used to instantiate events.
- `core/storage`: Exports an object which handles everything related to files.
- `core/wrappers`: Contains classes that wrap around values and provide extra functionality.
- `core/permissions`: The file containing everything related to permissions.
# Design Decisions
- All top-level files (relative to `src`/`dist`) should ideally be independent, one-time use scripts. This helps separate code that just initializes once and reusable code that forms the bulk of the main program itself. That's why all the file searching and loading commands/events will be done in `index`.
- Wrapper objects were designed with the idea of letting you assign functions directly to native objects [without the baggage of actually doing so](https://developer.mozilla.org/en-US/docs/Web/JavaScript/The_performance_hazards_of__%5B%5BPrototype%5D%5D_mutation).
- `test` should be a keyword for any file not tracked by git and generally be more flexible to play around with. It should also be automatically generated during initialization in `commands` so you can have templates ready for new commands.
- The storage module should not provide an auto-write feature. This would actually end up overcomplicating things especially when code isn't fully blocking.
- I think it's much easier to make a template system within the code itself. After all, the templates only change when the code changes to use new keys or remove old ones. You'll also be able to dedicate specific classes for the task rather than attaching meta tags to arrays and objects.
- I decided to forget about implementing dynamic events. I don't think it'll work with this setup. After all, there are only so many events you can use, whereas commands can have any number of ones, more suitable for dynamic loading. The main reasons were unsecure types and no easy way to access variables like the config or client.
- I want to make attaching subcommands more flexible, so you can either add subcommands in the constructor or by using a method. However, you have to add all other properties when instantiating a command.
- All commands should have only one parameter. This parameter is meant to be flexible so you can add properties without making a laundry list of parameters. It also has convenience functions too so you don't have to import the library for each command.
- The objects in `core/structures` are initialized into a special object once and then cached into memory automatically due to an import system. This means you don't have to keep loading JSON files over and over again even without the stack storage system. Because a JSON file resolves into an object, any extra keys are removed automatically (as it isn't initialized into the data) and any property that doesn't yet exist on the JSON object will be initialized into something. You can then have specific functions like `addUser` onto objects with a specific structure.
- There were several possible ways to go about implementing aliases and subaliases.
- Two properties on the `Command` class, `aliases: string[]` and `subaliases: {[key: string]: string[]}`.
- Exporting a const named `aliases` which would handle top-level aliases.
- For `subaliases`, either making subaliases work like redirects (Instead of doing `new Command(...)`, you'd do `"nameOfSubcommand"`), or define properties on `Command`.
- What I ended up doing for aliases is making an `aliases` property on `Command` and then converting those string arrays to a more usable structure with strings pointing to the original commands. `aliases` at the very top will determine global aliases and is pretty much the exception in the program's logic. `aliases` elsewhere will provide aliases per subcommand. For anything other than the top-level or `subcommands`, `aliases` does nothing (plus you'll get a warning about it).

4
package-lock.json generated
View File

@ -1,11 +1,11 @@
{
"name": "d.js-v12-bot",
"name": "travebot",
"version": "0.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "d.js-v12-bot",
"name": "travebot",
"version": "0.0.1",
"hasInstallScript": true,
"license": "MIT",

View File

@ -1,8 +1,17 @@
{
"name": "d.js-v12-bot",
"name": "travebot",
"version": "0.0.1",
"description": "A Discord bot built on Discord.JS v12",
"description": "TravBot Discord bot.",
"main": "dist/index.js",
"scripts": {
"build": "tsc --project tsconfig.prod.json && npm prune --production",
"start": "node .",
"once": "tsc && npm start",
"dev": "tsc-watch --onSuccess \"node . dev\"",
"test": "jest",
"format": "prettier --write **/*",
"postinstall": "husky install"
},
"dependencies": {
"canvas": "^2.7.0",
"chalk": "^4.1.0",
@ -34,19 +43,10 @@
"tsc-watch": "^4.2.9",
"typescript": "^3.9.7"
},
"scripts": {
"build": "tsc --project tsconfig.prod.json && npm prune --production",
"start": "node .",
"once": "tsc && npm start",
"dev": "tsc-watch --onSuccess \"node . dev\"",
"test": "jest",
"format": "prettier --write **/*",
"postinstall": "husky install"
},
"author": "Keanu Timmermans",
"license": "MIT",
"keywords": [
"discord.js",
"bot"
],
"author": "Keanu Timmermans",
"license": "MIT"
]
}