Skip to content

Commit

Permalink
magic madness
Browse files Browse the repository at this point in the history
  • Loading branch information
twlite committed Jan 3, 2024
1 parent 0b6f6b9 commit cbdf4f9
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 52 deletions.
11 changes: 11 additions & 0 deletions packages/commandkit/src/CommandKit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import colors from './utils/colors';

export class CommandKit {
#data: CommandKitData;
static instance: CommandKit;

/**
* Create a new command and event handler with CommandKit.
Expand All @@ -25,11 +26,21 @@ export class CommandKit {
);
}

CommandKit.instance = this;

this.#data = options;

this.#init();
}

getCommandHandler() {
return this.#data.commandHandler;
}

getClient() {
return this.#data.client;
}

/**
* (Private) Initialize CommandKit.
*/
Expand Down
98 changes: 54 additions & 44 deletions packages/commandkit/src/handlers/command-handler/CommandHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ import loadCommandsWithRest from './functions/loadCommandsWithRest';
import registerCommands from './functions/registerCommands';
import builtInValidationsFunctions from './validations';
import colors from '../../utils/colors';
import { createStore } from '../../utils/store';
import { Interaction } from 'discord.js';

interface CommandStore {
command: CommandFileObject;
interaction: Interaction;
}

/**
* A handler for client application commands.
*/
export class CommandHandler {
#data: CommandHandlerData;
public context = createStore<CommandStore>();

constructor({ ...options }: CommandHandlerOptions) {
this.#data = {
Expand Down Expand Up @@ -178,59 +186,61 @@ export class CommandHandler {
// Skip if autocomplete handler is not defined
if (isAutocomplete && !autocomplete) return;

const commandObj = {
data: targetCommand.data,
options: targetCommand.options,
...rest,
};

if (this.#data.validationHandler) {
let canRun = true;

for (const validationFunction of this.#data.validationHandler.validations) {
const stopValidationLoop = await validationFunction({
interaction,
commandObj,
client: this.#data.client,
handler: this.#data.commandkitInstance,
});

if (stopValidationLoop) {
canRun = false;
break;
this.context.run({ command: targetCommand, interaction }, async () => {
const commandObj = {
data: targetCommand.data,
options: targetCommand.options,
...rest,
};

if (this.#data.validationHandler) {
let canRun = true;

for (const validationFunction of this.#data.validationHandler.validations) {
const stopValidationLoop = await validationFunction({
interaction,
commandObj,
client: this.#data.client,
handler: this.#data.commandkitInstance,
});

if (stopValidationLoop) {
canRun = false;
break;
}
}
}

if (!canRun) return;
}

let canRun = true;
if (!canRun) return;
}

// If custom validations pass and !skipBuiltInValidations, run built-in CommandKit validation functions
if (!this.#data.skipBuiltInValidations) {
for (const validation of this.#data.builtInValidations) {
const stopValidationLoop = validation({
targetCommand,
interaction,
handlerData: this.#data,
});
let canRun = true;

if (stopValidationLoop) {
canRun = false;
break;
// If custom validations pass and !skipBuiltInValidations, run built-in CommandKit validation functions
if (!this.#data.skipBuiltInValidations) {
for (const validation of this.#data.builtInValidations) {
const stopValidationLoop = validation({
targetCommand,
interaction,
handlerData: this.#data,
});

if (stopValidationLoop) {
canRun = false;
break;
}
}
}
}

if (!canRun) return;
if (!canRun) return;

const context = {
interaction,
client: this.#data.client,
handler: this.#data.commandkitInstance,
};
const context = {
interaction,
client: this.#data.client,
handler: this.#data.commandkitInstance,
};

await targetCommand[isAutocomplete ? 'autocomplete' : 'run']!(context);
await targetCommand[isAutocomplete ? 'autocomplete' : 'run']!(context);
});
});
}

Expand Down
21 changes: 21 additions & 0 deletions packages/commandkit/src/hooks/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { CommandKit } from '..';

export const getCommandKit = () => {
const instance = CommandKit.instance;
if (!instance) {
throw new Error('CommandKit is not initialized.');
}

return instance;
};

export const getCommandHandler = () => {
const ckit = getCommandKit();
const handler = ckit.getCommandHandler();

if (!handler) {
throw new Error('CommandHandler is not initialized.');
}

return handler;
};
2 changes: 2 additions & 0 deletions packages/commandkit/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './useGuild';
export * from './useInteraction';
5 changes: 5 additions & 0 deletions packages/commandkit/src/hooks/useClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { getCommandKit } from './common';

export function useClient() {
return getCommandKit().getClient();
}
13 changes: 13 additions & 0 deletions packages/commandkit/src/hooks/useGuild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { getCommandHandler } from './common';

export function useGuild() {
const { context } = getCommandHandler();

const data = context.getStore();

if (!data) {
throw new Error('Cannot invoke "useGuild" outside of a command.');
}

return data.interaction.guild;
}
13 changes: 13 additions & 0 deletions packages/commandkit/src/hooks/useInteraction.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Interaction } from 'discord.js';
import { getCommandHandler } from './common';

export function useInteraction<T>(): T {
const { context } = getCommandHandler();

const data = context.getStore();
if (!data) {
throw new Error('Cannot invoke "useInteraction" outside of a command.');
}

return data.interaction as T;
}
1 change: 1 addition & 0 deletions packages/commandkit/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './CommandKit';
export * from './components';
export * from './hooks';
export * from './config';
export * from './utils/signal';
export type * from './types';
5 changes: 5 additions & 0 deletions packages/commandkit/src/utils/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { AsyncLocalStorage } from 'node:async_hooks';

export const createStore = <T = unknown>() => {
return new AsyncLocalStorage<T>();
};
9 changes: 6 additions & 3 deletions packages/commandkit/tests/src/commands/misc/count.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { SlashCommandProps, CommandOptions, CommandData } from '../../../../src';
import { ButtonKit, createEffect, createSignal } from '../../../../src/index';
import { ButtonStyle, ActionRowBuilder, ButtonInteraction } from 'discord.js';
import { ButtonKit, createEffect, createSignal, useInteraction } from '../../../../src/index';
import { ButtonStyle, ActionRowBuilder, ButtonInteraction, CommandInteraction } from 'discord.js';

export const data: CommandData = {
name: 'count',
Expand Down Expand Up @@ -39,7 +39,10 @@ function getButtons() {
return { dec, reset, inc, trash, row };
}

export async function run({ interaction }: SlashCommandProps) {
export async function run() {
const interaction = useInteraction<CommandInteraction<'cached'>>(); // ignore this type im using ts here
if (!interaction.channel) return;

const [count, setCount, disposeCountSubscribers] = createSignal(0);
const { dec, reset, inc, trash, row } = getButtons();

Expand Down
14 changes: 10 additions & 4 deletions packages/commandkit/tests/src/commands/misc/ping.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { ActionRowBuilder, ApplicationCommandOptionType, ButtonStyle } from 'discord.js';
import {
SlashCommandProps,
ActionRowBuilder,
ApplicationCommandOptionType,
ButtonStyle,
CommandInteraction,
} from 'discord.js';
import {
CommandOptions,
CommandData,
ButtonKit,
AutocompleteProps,
useInteraction,
} from '../../../../src/index';

export const data: CommandData = {
Expand Down Expand Up @@ -36,7 +41,8 @@ export async function autocomplete({ interaction }: AutocompleteProps) {
interaction.respond(filtered);
}

export async function run({ interaction, client }: SlashCommandProps) {
export async function run() {
const interaction = useInteraction<CommandInteraction<'cached'>>(); // ignore this type im using ts here
if (!interaction.channel) return;

const button = new ButtonKit()
Expand Down Expand Up @@ -73,5 +79,5 @@ export async function run({ interaction, client }: SlashCommandProps) {
}

export const options: CommandOptions = {
devOnly: true,
devOnly: false,
};
6 changes: 5 additions & 1 deletion packages/commandkit/tests/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CommandKit } from '../../src/index';
import { CommandKit, useInteraction } from '../../src/index';
import { Client } from 'discord.js';
// require('dotenv').config();

Expand All @@ -17,3 +17,7 @@ new CommandKit({
});

await client.login(process.env.TOKEN);

setTimeout(() => {
useInteraction();
});

0 comments on commit cbdf4f9

Please sign in to comment.