Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions backend/src/plugins/CommandAliases/CommandAliasesPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { guildPlugin } from "vety";
import { DispatchAliasEvt } from "./events/DispatchAliasEvt.js";
import { CommandAliasesPluginType, zCommandAliasesConfig } from "./types.js";
import { normalizeAliases } from "./functions/normalizeAliases.js";
import { buildAliasMatchers } from "./functions/buildAliasMatchers.js";
import { getGuildPrefix } from "../../utils/getGuildPrefix.js";

export const CommandAliasesPlugin = guildPlugin<CommandAliasesPluginType>()({
name: "command_aliases",
configSchema: zCommandAliasesConfig,

beforeLoad(pluginData) {
const prefix = getGuildPrefix(pluginData);
const config = pluginData.config.get();
const normalizedAliases = normalizeAliases(config.aliases);

pluginData.state.matchers = buildAliasMatchers(prefix, normalizedAliases);
},

events: [DispatchAliasEvt],
});
31 changes: 31 additions & 0 deletions backend/src/plugins/CommandAliases/docs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { ZeppelinPluginDocs } from "../../types.js";
import { zCommandAliasesConfig } from "./types.js";

export const commandAliasesPluginDocs: ZeppelinPluginDocs = {
type: "stable",
prettyName: "Command Aliases",
configSchema: zCommandAliasesConfig,
description: "This plugin lets you create shortcuts for existing commands.",
usageGuide: `
For example, you can make \`!b\` work the same as \`!ban\`, or \`!c\` work the same as \`!cases\`.

### Example

\`\`\`yaml
plugins:
command_aliases:
config:
aliases:
"b": "ban"
"c": "cases"
"b2": "ban -d 2"
"ownerinfo": "info 754421392988045383"
\`\`\`

With this setup:
- \`!b @User\` runs \`!ban @User\`
- \`!c\` runs \`!cases\`
- \`!b2 @User\` runs \`!ban -d 2 @User\`
- \`!ownerinfo\` runs \`!info 754421392988045383\`
`
};
24 changes: 24 additions & 0 deletions backend/src/plugins/CommandAliases/events/DispatchAliasEvt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Message } from "discord.js";
import { commandAliasesEvt } from "../types.js";

export const DispatchAliasEvt = commandAliasesEvt({
event: "messageCreate",
async listener({ args: { message: msg }, pluginData }) {
if (!msg.guild || !msg.content) return;
if (msg.author.bot || msg.webhookId) return;

const matchers = pluginData.state.matchers ?? [];
if (matchers.length === 0) return;

const matchingAlias = matchers.find((matcher) => matcher.regex.test(msg.content));
if (!matchingAlias) return;

const newContent = msg.content.replace(matchingAlias.regex, matchingAlias.replacement);
if (newContent === msg.content) return;

const copiedMessage = Object.create(msg);
copiedMessage.content = newContent;

await pluginData.getKnubInstance().dispatchMessageCommands(copiedMessage as Message);
},
});
17 changes: 17 additions & 0 deletions backend/src/plugins/CommandAliases/functions/buildAliasMatchers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import escapeStringRegexp from "escape-string-regexp";
import { NormalizedAlias } from "./normalizeAliases.js";

export interface AliasMatcher {
regex: RegExp;
replacement: string;
}

export function buildAliasMatchers(prefix: string, aliases: NormalizedAlias[]): AliasMatcher[] {
return aliases.map((alias) => {
const pattern = `^${escapeStringRegexp(prefix)}${escapeStringRegexp(alias.alias)}\\b`;
return {
regex: new RegExp(pattern, "i"),
replacement: `${prefix}${alias.target}`,
};
});
}
27 changes: 27 additions & 0 deletions backend/src/plugins/CommandAliases/functions/normalizeAliases.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
export interface NormalizedAlias {
alias: string;
target: string;
}

export function normalizeAliases(aliases: Record<string, string> | undefined | null): NormalizedAlias[] {
if (!aliases) {
return [];
}

const normalized: NormalizedAlias[] = [];
for (const [rawAlias, rawTarget] of Object.entries(aliases)) {
const alias = rawAlias.trim();
const target = rawTarget.trim();

if (!alias || !target) {
continue;
}

normalized.push({
alias,
target,
});
}

return normalized;
}
16 changes: 16 additions & 0 deletions backend/src/plugins/CommandAliases/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { BasePluginType, guildPluginEventListener } from "vety";
import z from "zod";
import { AliasMatcher } from "./functions/buildAliasMatchers.js";

export const zCommandAliasesConfig = z.strictObject({
aliases: z.record(z.string().min(1), z.string().min(1)).optional(),
});

export interface CommandAliasesPluginType extends BasePluginType {
configSchema: typeof zCommandAliasesConfig;
state: {
matchers: AliasMatcher[];
};
}

export const commandAliasesEvt = guildPluginEventListener<CommandAliasesPluginType>();
6 changes: 6 additions & 0 deletions backend/src/plugins/availablePlugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ import { UtilityPlugin } from "./Utility/UtilityPlugin.js";
import { utilityPluginDocs } from "./Utility/docs.js";
import { WelcomeMessagePlugin } from "./WelcomeMessage/WelcomeMessagePlugin.js";
import { welcomeMessagePluginDocs } from "./WelcomeMessage/docs.js";
import { CommandAliasesPlugin } from "./CommandAliases/CommandAliasesPlugin.js";
import { commandAliasesPluginDocs } from "./CommandAliases/docs.js";

export const availableGuildPlugins: ZeppelinGuildPluginInfo[] = [
{
Expand All @@ -100,6 +102,10 @@ export const availableGuildPlugins: ZeppelinGuildPluginInfo[] = [
plugin: CensorPlugin,
docs: censorPluginDocs,
},
{
plugin: CommandAliasesPlugin,
docs: commandAliasesPluginDocs,
},
{
plugin: CompanionChannelsPlugin,
docs: companionChannelsPluginDocs,
Expand Down
Loading