Skip to content

Commit 8a478a3

Browse files
committed
feat: create a Bot class and include Pino logger
1 parent a23e639 commit 8a478a3

File tree

9 files changed

+175
-19
lines changed

9 files changed

+175
-19
lines changed

jest.config.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
module.exports = {
22
preset: 'ts-jest',
33
testEnvironment: 'node',
4-
};
4+
moduleNameMapper: {
5+
'^#src/(.*)$': '<rootDir>/src/$1',
6+
},
7+
};

package-lock.json

Lines changed: 81 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
"version": "0.0.0",
44
"private": true,
55
"scripts": {
6-
"build": "tsc",
6+
"build": "tsc -p tsconfig.prod.json",
77
"check-types": "tsc --noEmit",
8-
"test-only": "jest",
98
"heroku-postbuild": "npm run build",
109
"lint": "eslint src --ext ts",
1110
"lint-fix": "npm run lint -- --fix",
1211
"start": "nodemon --watch \"src/**/*.ts\" -e ts --exec \"ts-node src/bot.ts\"",
13-
"test": "npm run test-only && npm run lint && npm run check-types"
12+
"test": "npm run test-only && npm run lint && npm run check-types",
13+
"test-only": "jest",
14+
"test-coverage": "jest --coverage"
1415
},
1516
"repository": {
1617
"type": "git",
@@ -24,11 +25,13 @@
2425
"dependencies": {
2526
"discord.js": "^12.3.1",
2627
"dotenv": "^8.2.0",
27-
"make-promises-safe": "^5.1.0"
28+
"make-promises-safe": "^5.1.0",
29+
"pino": "^6.7.0"
2830
},
2931
"devDependencies": {
3032
"@types/jest": "^26.0.14",
3133
"@types/node": "^14.11.8",
34+
"@types/pino": "^6.3.3",
3235
"@types/ws": "^7.2.7",
3336
"@typescript-eslint/eslint-plugin": "^4.4.1",
3437
"@typescript-eslint/parser": "^4.4.1",

src/bot.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
import 'make-promises-safe';
2-
import { Client } from 'discord.js';
32
import * as Dotenv from 'dotenv';
43

4+
import Bot from './framework/Bot';
5+
56
Dotenv.config();
67

7-
const client = new Client();
8+
const bot = new Bot({ token: process.env.DISCORD_TOKEN });
89

9-
client.on('ready', () => {
10-
console.log('Bot is ready');
10+
bot.start().then(() => {
11+
bot.logger.info('Bot started');
1112
});
12-
13-
client.login(process.env.DISCORD_TOKEN);

src/framework/Bot.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Client } from 'discord.js';
2+
import pino from 'pino';
3+
4+
export interface BotOptions {
5+
token?: string;
6+
}
7+
8+
export default class Bot {
9+
private token?: string;
10+
// @ts-expect-error: The client must be constructed when "start()" is called,
11+
// because it keeps the process alive.
12+
private client: Client;
13+
private started = false;
14+
15+
public logger: pino.Logger;
16+
17+
public constructor(options: BotOptions = {}) {
18+
this.token = options.token;
19+
this.logger = pino();
20+
}
21+
22+
public async start(): Promise<void> {
23+
if (this.started) {
24+
throw new Error('Bot can only be started once');
25+
}
26+
this.started = true;
27+
this.client = new Client();
28+
try {
29+
await this.client.login(this.token);
30+
} catch (error) {
31+
this.started = false;
32+
throw error;
33+
}
34+
}
35+
36+
public stop(): void {
37+
if (!this.started) {
38+
throw new Error('Bot was not started');
39+
}
40+
this.client.destroy();
41+
this.started = false;
42+
}
43+
}

tests/framework/Bot.spec.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Bot from '#src/framework/Bot';
2+
3+
const dummyOptions = { token: 'dummy' };
4+
5+
test('bot.start() throws if called with bad token', async () => {
6+
const bot = new Bot(dummyOptions);
7+
await expect(bot.start()).rejects.toThrow(/invalid token/);
8+
});
9+
10+
test('bot.start() throws if called twice', async () => {
11+
const bot = new Bot(dummyOptions);
12+
bot.start().catch(() => {
13+
// ignore
14+
});
15+
await expect(bot.start()).rejects.toThrow(/can only be started once/);
16+
});
17+
18+
test('bot.stop() throws if it was not started', () => {
19+
const bot = new Bot(dummyOptions);
20+
expect(() => bot.stop()).toThrow(/was not started/);
21+
});

tests/sum.spec.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

tsconfig.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,16 @@
11
{
2-
"include": ["src/**/*.ts"],
2+
"include": ["src/**/*.ts", "tests/**/*.ts"],
33
"compilerOptions": {
4+
"target": "ES2020",
5+
"lib": ["ES2020"],
46
"strict": true,
57
"outDir": "build",
8+
"moduleResolution": "node",
9+
"esModuleInterop": true,
10+
"rootDir": "./",
11+
"baseUrl": "./",
12+
"paths": {
13+
"#src/*": ["./src/*"]
14+
}
615
}
716
}

tsconfig.prod.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"extends": "./tsconfig.json",
3+
"exclude": ["tests"]
4+
}

0 commit comments

Comments
 (0)