Last active
November 4, 2019 12:28
-
-
Save y21/a7cc433e1a0f6b64b9b1931710b5b56d to your computer and use it in GitHub Desktop.
Pylon Client
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
interface ClientOptions { | |
owner: string; | |
description: string; | |
prefix: string; | |
commands?: Array<Command>; | |
}; | |
interface CommandOptions { | |
name: string; | |
enabled?: boolean; | |
flags: Array<Flag>; | |
run: (message: MessageData) => any; | |
}; | |
interface MessageData { | |
message: discord.Message; | |
args: Array<string>; | |
flags: Array<MatchedFlag>; | |
}; | |
interface MatchedFlag { | |
name: string; | |
value?: string; | |
}; | |
interface FlagOptions { | |
name: string; | |
description: string; | |
}; | |
class Client { | |
public owner: string; | |
public description: string; | |
public prefix: string; | |
public wrapper: any; | |
public commands: Array<Command>; | |
/* | |
* Constructs a client | |
* @param {any} wrapper The 'discord' namespace | |
* @param {ClientOptions} options Options to use for this instance | |
*/ | |
constructor(wrapper: any, options: ClientOptions) { | |
this.wrapper = wrapper; | |
this.owner = options.owner; | |
this.description = options.description; | |
this.prefix = options.prefix; | |
this.commands = options.commands || []; | |
discord.registerEventHandler(discord.Event.MESSAGE_CREATE, (message: discord.Message): void => { | |
const [command, ...args] = message.content.split(" "); | |
const commandInst: Command | undefined = this.commands.find(c => this.prefix + c.name === command); | |
// Command not found | |
if (!commandInst) return; | |
// Parse flags | |
const flags: Array<MatchedFlag> = Flag.parse(args.join(" ")); | |
commandInst.run({ args: args.map((k: string, i: number) => { | |
if (Flag.hasFlag(k)) { | |
return ""; | |
} else if (Flag.hasFlag(args[i - 1])) { | |
return ""; | |
} else return k; | |
}), flags, message }); | |
}); | |
} | |
/** | |
* Prevents everyone/here/role/user mentions by adding an invisible character in mention | |
* @param {string} src The string that should be escaped | |
*/ | |
static escapeMentions(src: string): string { | |
return src.replace(/<@[!&](\d+)>/g, "<@\u200b$1>").replace(/@(here|everyone)/g, "@\u200b$1"); | |
} | |
/** | |
* Returns the string in a codeblock | |
* @param {string} src The string that should be placed inside of a codeblock | |
* @param {string} lang The language of the returned codeblock | |
*/ | |
static codeblock(src: string, lang?: string): string { | |
return "```" + (lang || "") + "\n" + src + "\n```"; | |
} | |
}; | |
class Command { | |
public name: string; | |
public enabled: boolean; | |
public flags: Array<Flag>; | |
public run: (message: MessageData) => any; | |
constructor(options: CommandOptions) { | |
this.name = options.name; | |
this.enabled = options.enabled || true; | |
this.run = options.run; | |
this.flags = options.flags; | |
} | |
}; | |
class Flag { | |
public name: string; | |
public description: string; | |
public static FLAG_REGEX = /--(\w+)(?: )?(\w+)?/; | |
constructor(options: FlagOptions) { | |
this.name = options.name; | |
this.description = options.description; | |
} | |
static parse(src: string): Array<MatchedFlag> { | |
return (src.match(new RegExp(Flag.FLAG_REGEX, "g")) || []).map(m => { | |
// Assert since there is definitely going to be matches | |
const match: RegExpMatchArray = <RegExpMatchArray>(m.match(Flag.FLAG_REGEX)); | |
return { | |
name: match[1], | |
value: match[2] | |
}; | |
}); | |
} | |
static eraseFlags(src: string): string { | |
return src.replace(new RegExp(Flag.FLAG_REGEX, "g"), ""); | |
} | |
static hasFlag(src: string): boolean { | |
return Flag.FLAG_REGEX.test(src); | |
} | |
}; | |
const client: Client = new Client(discord, { | |
owner: "312715611413413889", | |
description: "Epic Pylon Bot", | |
prefix: "!" | |
}); | |
/** | |
* Example command: | |
* !say hello @here --lang js | |
* | |
* ```js | |
* hello @here | |
* ``` | |
* Due to calling Client.escapeMentions before sending the message, this would not mention "@here" even if it had permissions to do so, | |
* since Client.escapeMentions adds '\u200b' between @ and the ID (or here/everyone) in mentions | |
*/ | |
client.commands.push(<Command>{ | |
name: "say", | |
flags: [ | |
{ | |
name: "lang", | |
description: "The codeblock language for this response" | |
} | |
], | |
run: (data: MessageData) => { | |
const { message, args, flags } = data; | |
const language: MatchedFlag | undefined = flags.find(f => f.name === "lang"); | |
client.wrapper.sendMessage( | |
message.channel_id, | |
Client.codeblock( | |
Client.escapeMentions(args.join(" ")), | |
(language || {}).value | |
) | |
); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment