Skip to content

Commit

Permalink
::new:: => generics for properly inferring types
Browse files Browse the repository at this point in the history
  • Loading branch information
spuckhafte committed Sep 11, 2023
1 parent caf86b7 commit 271046d
Show file tree
Hide file tree
Showing 10 changed files with 84 additions and 55 deletions.
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ Fill up some details and you're ready to *go()* !<br>
```js
import { Command } from 'breezer.js/dist'

export default class extends Command {
export default class extends Command<[]> {
constructor() {
super({
structure: [],
Expand All @@ -67,9 +67,14 @@ export default class extends Command {
}
```
Every command is a class, child of the `Command` class.<br>
**Generic of class `Command<[]>`:** Defines the *type* of the structure of your cmd.
- helps in inferring the types of different fields returned by `this.extract()` *(explained later)*
`structure` - defines a structure for your command.
Helpful when extracting the fields of you commands.<br>
This property will be better understood in the next command. Here there are no fields for this cmd => no structure.<br>

*Reason why we define the structure twice is because, `Generic` helps in inferring the type properly and the property `structure` helps in actual conversion of field (say to number) and raising errors in `strict` mode.

`strict` - set it to true if you want to recieve errors/warnings when:
- user does not follow the defined structure of the cmd
- a deleted msg listens for certain state(s)
Expand All @@ -84,7 +89,7 @@ This feature should only be turned on during development.
```js
import { Command } from 'breezer.js'

export default class extends Command {
export default class extends Command<[string]> {
constructor() {
super({
structure: ['string'],
Expand All @@ -93,6 +98,7 @@ export default class extends Command {
}

async execute() {
// operation: string
const [operation] = this.extract();
let value;
try {
Expand Down Expand Up @@ -137,7 +143,7 @@ import { MessageEmbed } from 'discord.js';
const state = new StateManager({
count: 1
});
export default class extends Command {
export default class extends Command<[number]> {
constructor() {
super({
name: 'mul',
Expand All @@ -148,6 +154,7 @@ export default class extends Command {
});
}
async execute() {
// by: number
const [by] = this.extract();

await this.send({
Expand Down
6 changes: 3 additions & 3 deletions dist/helpers/command.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Message, PermissionResolvable } from "discord.js";
import { CmdStructure, CommandSettings, Payload } from "../../types";
import { StateManager } from "./stateManager.js";
export declare class Command {
export declare class Command<Structure extends (string | number | null)[]> {
structure: CmdStructure[];
name?: string;
strict: boolean;
Expand All @@ -13,7 +13,7 @@ export declare class Command {
till?: 'forever' | number;
constructor(settings: CommandSettings);
/**Extract fields from a command as per their defined structure */
extract(): (string | number)[];
extract(): Structure;
/**Add your logics for the command inside this function */
execute(): Promise<void>;
/**Send using this if there are states to manage */
Expand All @@ -23,7 +23,7 @@ export declare class Command {
/**Check if the bot has a specific perm */
botHasPerm(perm: PermissionResolvable): boolean | undefined;
}
export declare class TypicalCommand extends Command {
export declare class TypicalCommand<T extends []> extends Command<T> {
constructor();
execute(): Promise<void>;
}
5 changes: 4 additions & 1 deletion dist/helpers/funcs.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Message } from "discord.js";
import { Message, PermissionResolvable } from "discord.js";
export declare function err(desc: string, cmd?: string, warn?: boolean): string;
/**Listen to button interactions
* @param users - array of user-ids who can click on button, empty array => anyone can click
Expand All @@ -10,3 +10,6 @@ export declare function buttonSignal(users: string[], msg: Message | undefined,
max?: number;
time?: number;
}): import("discord.js").InteractionCollector<import("discord.js").MessageComponentInteraction<import("discord.js").CacheType>> | undefined;
/**Check if a user has a specific perm */
export declare function userHasPerm(perm: PermissionResolvable, userId: string, msg: Message): Promise<boolean>;
export declare function getIntents(): number[];
31 changes: 31 additions & 0 deletions dist/helpers/funcs.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Intents } from "discord.js";
export function err(desc, cmd, warn = false) {
return `[${warn ? 'warn' : 'err'}][cmd: ${cmd}] ${desc}`;
}
Expand All @@ -20,3 +30,24 @@ export function buttonSignal(users, msg, props) {
});
return collector;
}
/**Check if a user has a specific perm */
export function userHasPerm(perm, userId, msg) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const channel = msg.channel;
const user = yield ((_a = msg.guild) === null || _a === void 0 ? void 0 : _a.members.fetch(userId));
if (!user)
return false;
return channel.permissionsFor(user).has(perm);
});
}
export function getIntents() {
return [
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
Intents.FLAGS.MESSAGE_CONTENT,
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MEMBERS,
Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS
];
}
6 changes: 2 additions & 4 deletions dist/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import discord, { Message, PermissionResolvable } from 'discord.js';
import discord from 'discord.js';
import { Command } from './helpers/command.js';
import { StateManager } from './helpers/stateManager.js';
import { buttonSignal } from './helpers/funcs.js';
import { buttonSignal, userHasPerm } from './helpers/funcs.js';
declare class Bot {
commands: string[];
bot: discord.Client;
Expand All @@ -18,6 +18,4 @@ declare class Bot {
});
go(cb?: CallableFunction): Promise<void>;
}
/**Check if a user has a specific perm */
declare function userHasPerm(perm: PermissionResolvable, userId: string, msg: Message): Promise<boolean>;
export { Bot, Command, StateManager, buttonSignal, userHasPerm };
27 changes: 5 additions & 22 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import discord, { Intents } from 'discord.js';
import discord from 'discord.js';
import fs from 'fs';
import { revealNameOfCmd } from './helpers/handlers.js';
import { Command } from './helpers/command.js';
import { StateManager } from './helpers/stateManager.js';
import { buttonSignal } from './helpers/funcs.js';
import { buttonSignal, getIntents, userHasPerm } from './helpers/funcs.js';
class Bot {
constructor(options) {
let intents = [
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
Intents.FLAGS.MESSAGE_CONTENT,
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MEMBERS,
Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS
];
let intents = getIntents();
this.commands = fs.readdirSync(options.commandsFolder).map(i => i.replace(options.lang, ''));
this.token = options.token;
this.cmdFolder = options.commandsFolder;
Expand All @@ -31,7 +24,8 @@ class Bot {
this.bot = new discord.Client({ intents });
let cmdsCollectd = {};
for (let command of this.commands) {
import(`file://${process.cwd()}/${this.cmdFolder}/${command}${this.lang}`).then(cmd => {
const cmdPath = `file://${process.cwd()}/${this.cmdFolder}/${command}${this.lang}`;
import(cmdPath).then(cmd => {
if (cmd.default)
cmdsCollectd[command] = cmd.default;
}).catch(e => console.log(e));
Expand All @@ -57,15 +51,4 @@ class Bot {
});
}
}
/**Check if a user has a specific perm */
function userHasPerm(perm, userId, msg) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
const channel = msg.channel;
const user = yield ((_a = msg.guild) === null || _a === void 0 ? void 0 : _a.members.fetch(userId));
if (!user)
return false;
return channel.permissionsFor(user).has(perm);
});
}
export { Bot, Command, StateManager, buttonSignal, userHasPerm };
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "breezer.js",
"version": "0.4.9",
"version": "0.5.0",
"description": "",
"main": "dist/index.js",
"scripts": {
Expand Down
12 changes: 6 additions & 6 deletions src/helpers/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const regex = {
stateExp: /\$[a-zA-Z0-9-]+\$/g
}

export class Command {
export class Command<Structure extends (string|number|null)[]> {
structure:CmdStructure[];
name?:string;
strict:boolean;
Expand Down Expand Up @@ -100,13 +100,13 @@ export class Command {
}
}

const extracted:(string|number)[] = [];
const extracted = [] as unknown as Structure;
for (let field in fields) {
try {
if (+field == this.structure.length - 1 && +field !== fields.length - 1) {
if (this.structure[field].includes('string')) {
let value = fields.splice(+field).join(' ');
extracted.push(value);
extracted.push(value as never);
return extracted;
}
}
Expand All @@ -115,11 +115,11 @@ export class Command {
this.structure[field].split('|')[0] as 'number'|'string'
](fields[field], this.strict, this.name);

extracted.push(data);
extracted.push(data as never);
} catch (e) {
if (this.strict) {
throw Error(e as string);
} else extracted.push(fields[field]);
} else extracted.push(fields[field] as never);
}
}
return extracted;
Expand Down Expand Up @@ -171,7 +171,7 @@ export class Command {
}
}

export class TypicalCommand extends Command {
export class TypicalCommand<T extends []> extends Command<T> {
constructor() {
super({
structure: [],
Expand Down
13 changes: 12 additions & 1 deletion src/helpers/funcs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Message, PermissionResolvable, TextChannel } from "discord.js";
import { Intents, Message, PermissionResolvable, TextChannel } from "discord.js";

export function err(desc:string, cmd?:string, warn=false) {
return `[${warn ? 'warn' : 'err'}][cmd: ${cmd}] ${desc}`
Expand Down Expand Up @@ -35,4 +35,15 @@ export async function userHasPerm(perm:PermissionResolvable, userId:string, msg:
const user = await msg.guild?.members.fetch(userId);
if (!user) return false;
return channel.permissionsFor(user).has(perm);
}

export function getIntents() {
return [
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
Intents.FLAGS.MESSAGE_CONTENT,
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MEMBERS,
Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS
]
}
24 changes: 10 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,22 @@
import discord, { Intents, Message, PermissionResolvable, TextChannel } from 'discord.js';
import discord from 'discord.js';
import fs from 'fs';
import { TypicalCommand } from './helpers/command.js';
import { revealNameOfCmd } from './helpers/handlers.js';
import { Command } from './helpers/command.js';
import { StateManager } from './helpers/stateManager.js';
import { buttonSignal, userHasPerm } from './helpers/funcs.js';
import { buttonSignal, getIntents, userHasPerm } from './helpers/funcs.js';

class Bot {
commands:string[];
bot:discord.Client;
prefix:string;
private commandObjects:{ [index: string]: TypicalCommand };
private commandObjects:{ [index: string]: TypicalCommand<[]> };
private token:string;
private cmdFolder:string;
private lang:string

constructor(options:{ commandsFolder:string, token:string, prefix:string, lang:'.js'|'.ts' }) {
let intents = [
Intents.FLAGS.GUILD_MESSAGES,
Intents.FLAGS.GUILD_MESSAGE_REACTIONS,
Intents.FLAGS.MESSAGE_CONTENT,
Intents.FLAGS.GUILDS,
Intents.FLAGS.GUILD_MEMBERS,
Intents.FLAGS.GUILD_EMOJIS_AND_STICKERS
]
let intents = getIntents();

this.commands = fs.readdirSync(options.commandsFolder).map(i => i.replace(options.lang, ''));
this.token = options.token;
Expand All @@ -33,9 +26,10 @@ class Bot {

this.bot = new discord.Client({ intents });

let cmdsCollectd:{ [index: string]: TypicalCommand } = {};
let cmdsCollectd:{ [index: string]: TypicalCommand<[]> } = {};
for (let command of this.commands) {
import(`file://${process.cwd()}/${this.cmdFolder}/${command}${this.lang}`).then(cmd => {
const cmdPath = `file://${process.cwd()}/${this.cmdFolder}/${command}${this.lang}`;
import(cmdPath).then(cmd => {
if (cmd.default)
cmdsCollectd[command] = cmd.default;
}).catch(e => console.log(e));
Expand All @@ -48,9 +42,11 @@ class Bot {
this.bot.on('messageCreate', async msg => {
msg.content = msg.content.toLowerCase();
const cmdName = revealNameOfCmd(msg.content, this.prefix);

if (!cmdName || !this.commands.includes(cmdName)) return;
let cmdClass = this.commandObjects[cmdName] as any;
const cmd = new cmdClass() as TypicalCommand
const cmd = new cmdClass();

cmd.content = msg.content.replace(this.prefix, '').replace(/[ ]+/g, ' ').trim();
cmd.msg = msg;
cmd.execute();
Expand Down

0 comments on commit 271046d

Please sign in to comment.