bakit 1.0.0-beta.14 → 1.0.0-beta.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.d.ts +69 -32
  2. package/dist/index.js +549 -578
  3. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as discord_js from 'discord.js';
2
- import { Awaitable, ChatInputCommandInteraction, CacheType, Message, InteractionReplyOptions, MessageCreateOptions, User, Collection, RESTPostAPIApplicationCommandsJSONBody, Client, ClientOptions, IntentsBitField, ClientEvents } from 'discord.js';
3
- import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { Awaitable, ChatInputCommandInteraction, CacheType, Message, InteractionReplyOptions, MessageCreateOptions, User, Collection, RESTPostAPIApplicationCommandsJSONBody, ClientOptions, Client, IntentsBitField, ClientEvents } from 'discord.js';
4
3
  import { SetOptional } from 'type-fest';
4
+ import { AsyncLocalStorage } from 'node:async_hooks';
5
5
  import EventEmitter from 'node:events';
6
6
 
7
7
  type ConstructorLike = new (...args: unknown[]) => object;
@@ -91,13 +91,15 @@ declare class SubcommandEntry extends BaseCommandEntry {
91
91
  parent: BaseCommandGroupEntry;
92
92
  constructor(options: BaseCommandEntryOptions, parent: BaseCommandGroupEntry);
93
93
  }
94
+ type CommandEntry = RootCommandEntry | CommandGroupEntry | SubcommandEntry;
94
95
 
95
96
  declare enum ArgumentType {
96
97
  String = "string",
97
98
  Integer = "integer",
98
99
  Number = "number",
99
100
  User = "user",
100
- Member = "member"
101
+ Member = "member",
102
+ Literal = "literal"
101
103
  }
102
104
  interface BaseArgumentOptions {
103
105
  type: ArgumentType;
@@ -127,13 +129,17 @@ interface UserArgumentOptions extends BaseArgumentOptions {
127
129
  interface MemberArgumentOptions extends BaseArgumentOptions {
128
130
  type: ArgumentType.Member;
129
131
  }
132
+ interface LiteralArgumentOptions extends Omit<BaseArgumentOptions, "name"> {
133
+ type: ArgumentType.Literal;
134
+ value: string;
135
+ }
130
136
  type ArgumentOptions = StringArgumentOptions | IntegerArgumentOptions | NumberArgumentOptions | UserArgumentOptions | MemberArgumentOptions;
131
137
 
132
138
  declare function getMethodArguments(method: CommandHook["method"]): readonly ArgumentOptions[];
133
139
  declare function getMethodArguments(method: CommandHook["method"], init: true): ArgumentOptions[];
134
140
  declare function createArgument<Options extends ArgumentOptions>(type: Options["type"]): (options: Omit<Options, "type"> | string) => (target: object, key: string | symbol, _index: number) => void;
135
- declare function describeArgumentExpectation(arg: ArgumentOptions): string;
136
- declare function format(arg: ArgumentOptions): string;
141
+ declare function describeArgumentExpectation(arg: ArgumentOptions | LiteralArgumentOptions): string;
142
+ declare function format(arg: ArgumentOptions | LiteralArgumentOptions): string;
137
143
  declare const Arg: {
138
144
  getMethodArguments: typeof getMethodArguments;
139
145
  createArgument: typeof createArgument;
@@ -146,6 +152,36 @@ declare const Arg: {
146
152
  member: (options: string | Omit<MemberArgumentOptions, "type">) => (target: object, key: string | symbol, _index: number) => void;
147
153
  };
148
154
 
155
+ interface ArgumentResolverOptions {
156
+ message: Message;
157
+ values: string[];
158
+ prefix: string;
159
+ }
160
+ declare class ArgumentResolver {
161
+ private _values;
162
+ prefix: string;
163
+ message: Message;
164
+ private _parsedValues;
165
+ private _args;
166
+ constructor(_values: string[], prefix: string, message: Message);
167
+ get commandName(): string;
168
+ get values(): readonly string[];
169
+ get parsedValues(): readonly unknown[];
170
+ get args(): readonly (ArgumentOptions | LiteralArgumentOptions)[];
171
+ get client(): BakitClient<true>;
172
+ static initialize(message: Message): Promise<ArgumentResolver | undefined>;
173
+ resolve(entry: CommandEntry, at?: number): Promise<void>;
174
+ protected parseExact(args: ArgumentOptions[], values: string[]): Promise<unknown[]>;
175
+ protected parseFlexible(args: ArgumentOptions[], values: string[]): Promise<unknown[]>;
176
+ private matchValue;
177
+ private matchUserValue;
178
+ private matchMemberValue;
179
+ private matchIntegerValue;
180
+ private matchNumberValue;
181
+ private matchStringValue;
182
+ static resolveChatInputOption(interaction: ChatInputCommandInteraction, arg: ArgumentOptions): string | number | discord_js.GuildMember | discord_js.User | discord_js.APIInteractionDataResolvedGuildMember | null;
183
+ }
184
+
149
185
  declare namespace CommandAPI {
150
186
  function use(root: RootCommandEntry): (target: ConstructorLike) => void;
151
187
  function getRoot(constructor: ConstructorLike): RootCommandEntry | undefined;
@@ -199,9 +235,31 @@ declare class CommandSyntaxError extends Error {
199
235
  get name(): string;
200
236
  }
201
237
 
202
- type GetSyntaxErrorMessageFunction = (command: object, error: CommandSyntaxError, context: MessageContext, args: readonly ArgumentOptions[], prefix: string) => Awaitable<MessageCreateOptions | undefined>;
238
+ type GetSyntaxErrorMessageFunction = (command: object, error: CommandSyntaxError, context: MessageContext, resolver: ArgumentResolver) => Awaitable<MessageCreateOptions | undefined>;
239
+ declare const defaultGetSyntaxErrorMessage: GetSyntaxErrorMessageFunction;
240
+
241
+ declare class CommandDispatcher {
242
+ client: BakitClient;
243
+ constructor(client: BakitClient);
244
+ getPrefixes(message: Message): Promise<string[]>;
245
+ handleChatInput(interaction: ChatInputCommandInteraction): Promise<void>;
246
+ private getChatInputTriggerChain;
247
+ private resolveChatInputEntry;
248
+ handleMessage(message: Message): Promise<void>;
249
+ private resolveCommandEntryChain;
250
+ private executeChain;
251
+ private executeHooks;
252
+ }
253
+
254
+ declare class DispatcherManager {
255
+ client: BakitClient;
256
+ command: CommandDispatcher;
257
+ constructor(client: BakitClient);
258
+ }
259
+
260
+ type GetPrefixFunction = (message: Message) => Awaitable<string[] | string>;
203
261
  interface BakitClientOptions extends ClientOptions {
204
- prefixes?: string[];
262
+ prefixes?: (string | GetPrefixFunction)[];
205
263
  enableMentionPrefix?: boolean;
206
264
  getSyntaxErrorMessage?: GetSyntaxErrorMessageFunction | null;
207
265
  }
@@ -209,25 +267,16 @@ declare class BakitClient<Ready extends boolean = boolean> extends Client<Ready>
209
267
  options: Omit<BakitClientOptions, "intents"> & {
210
268
  intents: IntentsBitField;
211
269
  };
270
+ dispatchers: DispatcherManager;
212
271
  constructor(options: BakitClientOptions);
213
- static getSyntaxErrorMessage: GetSyntaxErrorMessageFunction;
214
- private registerApplicationCommands;
215
- private handleMessage;
216
- private handleInteraction;
217
- private handleChatInputHooks;
218
- private handleMessageHooks;
219
- private handleChildMessageHooks;
220
- private runMessageHooks;
221
- private runChatInputHooks;
222
- private runHooks;
223
- private getChatInputTargetHooks;
272
+ isReady(): this is BakitClient<true>;
273
+ private initializeHandlers;
224
274
  }
225
275
 
226
276
  declare function extractId(value: string): string | null;
227
277
 
228
278
  type States = Record<string | symbol, unknown>;
229
279
  declare class StateBox {
230
- private static readonly STATES_KEY;
231
280
  static storage: AsyncLocalStorage<States>;
232
281
  private static getState;
233
282
  static run<R>(fn: () => R, store?: {}): R;
@@ -298,16 +347,4 @@ declare abstract class ListenerRegistry {
298
347
  static load(pattern: string, parallel?: boolean): Promise<ConstructorLike[]>;
299
348
  }
300
349
 
301
- /**
302
- * This file is used to redeclare original client to the custom one
303
- * Most of the structure is from Base, but some might be not
304
- */
305
-
306
-
307
- declare module "discord.js" {
308
- interface Base {
309
- client: BakitClient<true>;
310
- }
311
- }
312
-
313
- export { Arg, type ArgumentOptions, ArgumentType, BakitClient, type BakitClientOptions, type BaseArgumentOptions, BaseCommandEntry, type BaseCommandEntryOptions, BaseCommandGroupEntry, BaseContext, ChatInputContext, type ChatInputContextSendOptions, Command, CommandAPI, CommandFactory, CommandGroupEntry, type CommandHook, CommandRegistry, CommandSyntaxError, type CommandSyntaxErrorOptions, CommandSyntaxErrorType, type Context, type ContextSendOptions, type CreateCommandOptions, type ErrorCommandHookMethod, type ErrorListenerHookMethod, type EventsLike, type GetSyntaxErrorMessageFunction, type IntegerArgumentOptions, Listener, ListenerAPI, ListenerEntry, type ListenerEntryOptions, ListenerFactory, type ListenerHook, ListenerRegistry, type MainCommandHookMethod, type MainListenerHookMethod, type MemberArgumentOptions, MessageContext, type MessageContextSendOptions, type NumberArgumentOptions, RootCommandEntry, StateBox, type States, type StringArgumentOptions, SubcommandEntry, type UserArgumentOptions, extractId };
350
+ export { Arg, type ArgumentOptions, ArgumentResolver, type ArgumentResolverOptions, ArgumentType, BakitClient, type BakitClientOptions, type BaseArgumentOptions, BaseCommandEntry, type BaseCommandEntryOptions, BaseCommandGroupEntry, BaseContext, ChatInputContext, type ChatInputContextSendOptions, Command, CommandAPI, type CommandEntry, CommandFactory, CommandGroupEntry, type CommandHook, CommandRegistry, CommandSyntaxError, type CommandSyntaxErrorOptions, CommandSyntaxErrorType, type Context, type ContextSendOptions, type CreateCommandOptions, type ErrorCommandHookMethod, type ErrorListenerHookMethod, type EventsLike, type GetPrefixFunction, type GetSyntaxErrorMessageFunction, type IntegerArgumentOptions, Listener, ListenerAPI, ListenerEntry, type ListenerEntryOptions, ListenerFactory, type ListenerHook, ListenerRegistry, type LiteralArgumentOptions, type MainCommandHookMethod, type MainListenerHookMethod, type MemberArgumentOptions, MessageContext, type MessageContextSendOptions, type NumberArgumentOptions, RootCommandEntry, StateBox, type States, type StringArgumentOptions, SubcommandEntry, type UserArgumentOptions, defaultGetSyntaxErrorMessage, extractId };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { Collection, SlashCommandBuilder, SlashCommandSubcommandGroupBuilder, SlashCommandSubcommandBuilder, ChatInputCommandInteraction, Message, Client, Events, codeBlock } from 'discord.js';
1
+ import { Collection, SlashCommandBuilder, SlashCommandSubcommandGroupBuilder, SlashCommandSubcommandBuilder, ChatInputCommandInteraction, Message, codeBlock, Client, Events } from 'discord.js';
2
+ import { AsyncLocalStorage } from 'async_hooks';
2
3
  import glob from 'tiny-glob';
3
4
  import { pathToFileURL } from 'url';
4
- import { AsyncLocalStorage } from 'async_hooks';
5
5
 
6
6
  // src/BakitClient.ts
7
7
 
@@ -49,63 +49,177 @@ var BaseEntry = class {
49
49
  }
50
50
  };
51
51
 
52
- // src/command/CommandEntry.ts
53
- var BaseCommandEntry = class extends BaseEntry {
52
+ // src/listener/ListenerEntry.ts
53
+ var ListenerEntry = class extends BaseEntry {
54
54
  constructor(options) {
55
55
  super();
56
56
  this.options = options;
57
57
  }
58
- }, BaseCommandGroupEntry = class extends BaseCommandEntry {
59
- children = new Collection();
60
- subcommand(options) {
61
- let fullOptions = typeof options == "string" ? { name: options, description: `${options} command` } : { description: `${options.name} command`, ...options };
62
- if (this.children.has(fullOptions.name))
63
- throw new Error(`Entry "${fullOptions.name}" is already existed.`);
64
- let subcommand = new SubcommandEntry(fullOptions, this);
65
- return this.children.set(fullOptions.name, subcommand), subcommand;
58
+ };
59
+
60
+ // src/listener/Listener.ts
61
+ var ListenerAPI;
62
+ ((ListenerAPI2) => {
63
+ let entries = /* @__PURE__ */ new WeakMap();
64
+ function use(entry) {
65
+ return (target) => {
66
+ entries.set(target, entry);
67
+ };
66
68
  }
67
- }, RootCommandEntry = class extends BaseCommandGroupEntry {
68
- group(options) {
69
- let fullOptions = typeof options == "string" ? { name: options, description: `${options} command` } : { description: `${options.name} command`, ...options };
70
- if (this.children.has(fullOptions.name))
71
- throw new Error(`Entry "${fullOptions.name}" is already existed.`);
72
- let group = new CommandGroupEntry(fullOptions, this);
73
- return this.children.set(fullOptions.name, group), group;
69
+ ListenerAPI2.use = use;
70
+ function getEntry(target) {
71
+ return entries.get(target);
74
72
  }
75
- }, CommandGroupEntry = class extends BaseCommandGroupEntry {
76
- constructor(options, parent) {
77
- super(options);
78
- this.parent = parent;
73
+ ListenerAPI2.getEntry = getEntry;
74
+ })(ListenerAPI ||= {});
75
+ function ListenerFactory(options) {
76
+ let fullOptions = typeof options != "object" ? { name: options, once: false } : { once: false, ...options };
77
+ return new ListenerEntry(fullOptions);
78
+ }
79
+ var Listener = Object.assign(ListenerFactory, ListenerAPI);
80
+ var StateBox = class _StateBox {
81
+ static storage = new AsyncLocalStorage();
82
+ static getState() {
83
+ let state = this.storage.getStore();
84
+ if (!state)
85
+ throw new Error("No active context, did you forget to wrap it with StateBox.wrap()?");
86
+ return state;
79
87
  }
80
- }, SubcommandEntry = class extends BaseCommandEntry {
81
- constructor(options, parent) {
82
- super(options);
83
- this.parent = parent;
88
+ static run(fn, store2 = {}) {
89
+ return this.storage.run(store2, fn);
90
+ }
91
+ static wrap(fn) {
92
+ let currentStore = this.storage.getStore();
93
+ if (!currentStore)
94
+ throw new Error("No active context, cannot wrap function outside a StateBox.run()");
95
+ return () => this.run(fn, currentStore);
96
+ }
97
+ static use(defaultValue) {
98
+ return (target, key) => {
99
+ let generalKey = key;
100
+ Object.defineProperty(target, key, {
101
+ get() {
102
+ let states = _StateBox.getState();
103
+ return key in states || (states[generalKey] = defaultValue), states[generalKey];
104
+ },
105
+ set(value) {
106
+ let states = _StateBox.getState();
107
+ states[generalKey] = value;
108
+ },
109
+ enumerable: true,
110
+ configurable: true
111
+ });
112
+ };
84
113
  }
85
114
  };
86
-
87
- // src/command/Command.ts
88
- var CommandAPI;
89
- ((CommandAPI2) => {
90
- let rootEntries = /* @__PURE__ */ new WeakMap();
91
- function use(root) {
92
- return (target) => {
93
- root.setTarget(target), rootEntries.set(target, root);
115
+ var ListenerRegistry = class {
116
+ static client;
117
+ static constructors = /* @__PURE__ */ new Set();
118
+ static instances = /* @__PURE__ */ new WeakMap();
119
+ static executors = /* @__PURE__ */ new WeakMap();
120
+ /**
121
+ * Add and register a listener to the registry.
122
+ * If `options.emitter` is not provided, the registry will use the base `client` by default.
123
+ * @param constructor The listener class you want to add.
124
+ */
125
+ static add(constructor) {
126
+ let entry = Listener.getEntry(constructor);
127
+ if (!entry)
128
+ throw new Error(`No entry found for "${constructor.name}"`);
129
+ let { options } = entry;
130
+ if (!options.emitter) {
131
+ if (!this.client)
132
+ throw new Error("Client is not ready.");
133
+ options.emitter = this.client;
134
+ }
135
+ let instance = new constructor(), executor = this.createExecutor(constructor, instance);
136
+ this.constructors.add(constructor), this.instances.set(constructor, instance), this.executors.set(instance, executor), options.emitter[options.once ? "once" : "on"](options.name, (...args) => {
137
+ executor(...args);
138
+ });
139
+ }
140
+ /**
141
+ * Remove and unregister a listener from the registry.
142
+ * @param constructor The listener class you want to remove.
143
+ * @returns `boolean`, returns `true` if the listener is removed successfully.
144
+ */
145
+ static remove(constructor) {
146
+ let entry = Listener.getEntry(constructor);
147
+ if (!entry)
148
+ return false;
149
+ this.constructors.delete(constructor);
150
+ let instance = this.instances.get(constructor);
151
+ if (!instance)
152
+ return false;
153
+ this.instances.delete(constructor);
154
+ let executor = this.executors.get(instance);
155
+ if (!executor)
156
+ return false;
157
+ let { name, emitter } = entry.options;
158
+ return emitter?.removeListener(name, executor), this.executors.delete(instance), true;
159
+ }
160
+ /**
161
+ * Remove and unregister all listeners from the registry.
162
+ * @returns Amount of removed listeners.
163
+ */
164
+ static removeAll() {
165
+ let removedAmount = 0;
166
+ for (let constructor of this.constructors)
167
+ this.remove(constructor) && removedAmount++;
168
+ return removedAmount;
169
+ }
170
+ /**
171
+ * Set base client for the registry to fallback as default emitter. This should be used only by BakitClient and stay untouched.
172
+ * @param newClient base client to set for the registry.
173
+ */
174
+ static setClient(newClient) {
175
+ this.client = newClient;
176
+ }
177
+ static createExecutor(constructor, instance) {
178
+ let entry = Listener.getEntry(constructor);
179
+ if (!entry)
180
+ throw new Error("Missing listener entry");
181
+ let { hooks } = entry, execute = async (...args) => {
182
+ let mainHook = hooks.MAIN, preHook = hooks.PRE, postHook = hooks.POST, errorHook = hooks.ERROR;
183
+ if (mainHook)
184
+ try {
185
+ preHook && await preHook.method.call(instance, ...args), await mainHook.method.call(instance, ...args), postHook && await postHook.method.call(instance, ...args);
186
+ } catch (error) {
187
+ if (errorHook)
188
+ await errorHook.method.call(
189
+ instance,
190
+ error,
191
+ ...args
192
+ );
193
+ else
194
+ throw error;
195
+ }
196
+ };
197
+ return async (...args) => {
198
+ await StateBox.run(() => execute(...args));
94
199
  };
95
200
  }
96
- CommandAPI2.use = use;
97
- function getRoot(constructor) {
98
- return rootEntries.get(constructor);
201
+ /**
202
+ * Load and add all listeners which matched provided glob pattern to the registry.
203
+ * @param pattern glob pattern to load.
204
+ * @param parallel load all matched results in parallel, enabled by default.
205
+ * @returns All loaded listener constructors.
206
+ */
207
+ static async load(pattern, parallel = true) {
208
+ let loaders = (await glob(pattern)).map(async (file) => {
209
+ let fileURL = pathToFileURL(file).toString(), { default: constructor } = await import(fileURL);
210
+ return this.add(constructor), constructor;
211
+ });
212
+ if (parallel)
213
+ return Promise.all(loaders);
214
+ let result = [];
215
+ for (let loader of loaders)
216
+ result.push(await loader);
217
+ return result;
99
218
  }
100
- CommandAPI2.getRoot = getRoot;
101
- })(CommandAPI ||= {});
102
- function CommandFactory(options) {
103
- return typeof options == "string" && (options = { name: options }), options.description || (options.description = options.name), new RootCommandEntry(options);
104
- }
105
- var Command = Object.assign(CommandFactory, CommandAPI);
219
+ };
106
220
 
107
221
  // src/command/argument/Argument.ts
108
- var ArgumentType = /* @__PURE__ */ ((ArgumentType2) => (ArgumentType2.String = "string", ArgumentType2.Integer = "integer", ArgumentType2.Number = "number", ArgumentType2.User = "user", ArgumentType2.Member = "member", ArgumentType2))(ArgumentType || {});
222
+ var ArgumentType = /* @__PURE__ */ ((ArgumentType2) => (ArgumentType2.String = "string", ArgumentType2.Integer = "integer", ArgumentType2.Number = "number", ArgumentType2.User = "user", ArgumentType2.Member = "member", ArgumentType2.Literal = "literal", ArgumentType2))(ArgumentType || {});
109
223
 
110
224
  // src/command/argument/Arg.ts
111
225
  var store = /* @__PURE__ */ new WeakMap();
@@ -141,7 +255,9 @@ function describeArgumentExpectation(arg) {
141
255
  return parts.join(", ");
142
256
  }
143
257
  function format(arg) {
144
- let { name, required, tuple } = arg, opening = required ? "<" : "[", closing = required ? ">" : "]";
258
+ if (arg.type === "literal" /* Literal */)
259
+ return arg.value;
260
+ let { required, tuple, name } = arg, opening = required ? "<" : "[", closing = required ? ">" : "]";
145
261
  return `${opening}${tuple ? "..." : ""}${name}: ${describeArgumentExpectation(arg)}${closing}`;
146
262
  }
147
263
  var Arg = {
@@ -156,24 +272,263 @@ var Arg = {
156
272
  member
157
273
  };
158
274
 
159
- // src/command/CommandRegistry.ts
160
- var CommandRegistry = class _CommandRegistry {
161
- static constructors = new Collection();
162
- static instances = new Collection();
163
- /**
164
- * Add a command to the registry.
165
- * @param constructor The command class you want to add.
166
- */
167
- static add(constructor) {
168
- let root = Command.getRoot(constructor);
169
- if (!root)
170
- throw new Error(`No root found for "${constructor.name}"`);
171
- let { options } = root;
172
- this.constructors.set(options.name, constructor), this.instances.set(options.name, new constructor());
275
+ // src/utils/user.ts
276
+ function extractId(value) {
277
+ let idMatch = value.match(/^<@!?(\d+)>$/);
278
+ if (idMatch)
279
+ return idMatch[1];
280
+ let numericMatch = value.match(/^(\d{17,19})$/);
281
+ return numericMatch ? numericMatch[1] : null;
282
+ }
283
+
284
+ // src/errors/CommandSyntaxError.ts
285
+ var CommandSyntaxErrorType = /* @__PURE__ */ ((CommandSyntaxErrorType2) => (CommandSyntaxErrorType2.MissingRequireArgument = "MISSING_REQUIRE_ARGUMENT", CommandSyntaxErrorType2.InvalidArgument = "INVALID_ARGUMENT", CommandSyntaxErrorType2.InvalidVariadicArgumentValue = "INVALID_VARIADIC_ARGUMENT_VALUE", CommandSyntaxErrorType2))(CommandSyntaxErrorType || {}), CommandSyntaxError = class extends Error {
286
+ arg;
287
+ type;
288
+ expected;
289
+ received;
290
+ constructor(options) {
291
+ let message, { arg, type, received } = options, expected = Arg.describeArgumentExpectation(arg);
292
+ switch (type) {
293
+ case "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */: {
294
+ message = [`Missing required argument "${arg.name}"`, `> Expected: ${expected}`].join(`
295
+ `);
296
+ break;
297
+ }
298
+ case "INVALID_ARGUMENT" /* InvalidArgument */: {
299
+ message = [
300
+ `Invalid value received for argument "${arg.name}"`,
301
+ `> Expected: ${expected}`,
302
+ `> Received: ${String(received)}`
303
+ ].join(`
304
+ `);
305
+ break;
306
+ }
307
+ case "INVALID_VARIADIC_ARGUMENT_VALUE" /* InvalidVariadicArgumentValue */: {
308
+ message = [
309
+ `Invalid value received for variadic argument "${arg.name}"`,
310
+ `> Expected: ${expected}`,
311
+ `> Received: ${String(received)}`
312
+ ].join(`
313
+ `);
314
+ break;
315
+ }
316
+ default: {
317
+ message = "Unknown error";
318
+ break;
319
+ }
320
+ }
321
+ super(message), this.arg = arg, this.type = type, this.expected = expected, this.received = received, Error.captureStackTrace(this, this.constructor);
173
322
  }
174
- /**
175
- * Load and add all commands which matched provided glob pattern to the registry.
176
- * @param pattern glob pattern to load.
323
+ get name() {
324
+ return `CommandSyntaxError[${this.type}]`;
325
+ }
326
+ };
327
+
328
+ // src/command/argument/ArgumentResolver.ts
329
+ var ArgumentResolver = class _ArgumentResolver {
330
+ constructor(_values, prefix, message) {
331
+ this._values = _values;
332
+ this.prefix = prefix;
333
+ this.message = message;
334
+ }
335
+ _parsedValues = [];
336
+ _args = [];
337
+ get commandName() {
338
+ return this._values[0];
339
+ }
340
+ get values() {
341
+ return this._values;
342
+ }
343
+ get parsedValues() {
344
+ return this._parsedValues;
345
+ }
346
+ get args() {
347
+ return this._args;
348
+ }
349
+ get client() {
350
+ return this.message.client;
351
+ }
352
+ static async initialize(message) {
353
+ let prefix = (await message.client.dispatchers.command.getPrefixes(message)).find((p) => message.content.startsWith(p));
354
+ if (!prefix)
355
+ return;
356
+ let values = message.content.slice(prefix.length).trim().split(/\s+/);
357
+ return new _ArgumentResolver(values, prefix, message);
358
+ }
359
+ async resolve(entry, at = 1) {
360
+ let mainHook = entry.hooks.MAIN, args = mainHook ? [...Arg.getMethodArguments(mainHook.method)] : [], nextAt = at;
361
+ if (args.length) {
362
+ let values = this.values.slice(at), parsedValues = args.length >= values.length ? await this.parseExact(args, values) : await this.parseFlexible(args, values);
363
+ nextAt += parsedValues.length, this._args.push(...args), this._parsedValues.push(...parsedValues);
364
+ }
365
+ let nextValue = this._values[nextAt];
366
+ if (!nextValue || !("children" in entry))
367
+ return;
368
+ let childEntry = entry.children.get(nextValue);
369
+ childEntry && (this._args.push({
370
+ type: "literal" /* Literal */,
371
+ value: nextValue
372
+ }), await this.resolve(childEntry, nextAt + 1));
373
+ }
374
+ async parseExact(args, values) {
375
+ let parsedValues = [];
376
+ for (let i = 0; i < args.length; i++) {
377
+ let arg = args[i], value = values[i], matchedValue = await this.matchValue(arg, value);
378
+ if (matchedValue === null)
379
+ throw new CommandSyntaxError({
380
+ arg,
381
+ type: "INVALID_ARGUMENT" /* InvalidArgument */,
382
+ received: value
383
+ });
384
+ parsedValues.push(matchedValue);
385
+ }
386
+ return parsedValues;
387
+ }
388
+ async parseFlexible(args, values) {
389
+ let argIndex = 0, valueIndex = 0, parsedValues = [];
390
+ for (; argIndex < args.length; ) {
391
+ let arg = args[argIndex], value = values[valueIndex], matchedValue = await this.matchValue(arg, value);
392
+ if (matchedValue !== null)
393
+ parsedValues.push(matchedValue), valueIndex++;
394
+ else if (arg.required)
395
+ throw new CommandSyntaxError({
396
+ type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
397
+ received: value,
398
+ arg
399
+ });
400
+ argIndex++;
401
+ }
402
+ return parsedValues;
403
+ }
404
+ async matchValue(arg, value) {
405
+ if (!value)
406
+ return null;
407
+ switch (arg.type) {
408
+ case "user" /* User */:
409
+ return await this.matchUserValue(arg, value);
410
+ case "member" /* Member */:
411
+ return await this.matchMemberValue(arg, value);
412
+ case "integer" /* Integer */:
413
+ return this.matchIntegerValue(arg, value);
414
+ case "number" /* Number */:
415
+ return this.matchNumberValue(arg, value);
416
+ case "string" /* String */:
417
+ return this.matchStringValue(arg, value);
418
+ default:
419
+ return null;
420
+ }
421
+ }
422
+ async matchUserValue(arg, value) {
423
+ let userId = extractId(value);
424
+ return userId ? await this.client.users.fetch(userId).catch(() => null) : null;
425
+ }
426
+ async matchMemberValue(arg, value) {
427
+ let userId = extractId(value);
428
+ if (!userId)
429
+ return;
430
+ let { guild } = this.message;
431
+ if (guild)
432
+ return await guild.members.fetch(userId).catch(() => null);
433
+ }
434
+ matchIntegerValue(arg, value) {
435
+ let intVal = parseInt(value, 10);
436
+ return isNaN(intVal) || arg.minValue !== void 0 && intVal < arg.minValue || arg.maxValue !== void 0 && intVal > arg.maxValue ? null : intVal;
437
+ }
438
+ matchNumberValue(arg, value) {
439
+ let numVal = parseFloat(value);
440
+ return isNaN(numVal) || arg.minValue !== void 0 && numVal < arg.minValue || arg.maxValue !== void 0 && numVal > arg.maxValue ? null : numVal;
441
+ }
442
+ matchStringValue(arg, value) {
443
+ return arg.minLength !== void 0 && value.length < arg.minLength || arg.maxLength !== void 0 && value.length > arg.maxLength ? null : value;
444
+ }
445
+ static resolveChatInputOption(interaction, arg) {
446
+ switch (arg.type) {
447
+ case "string" /* String */:
448
+ return interaction.options.getString(arg.name, arg.required);
449
+ case "integer" /* Integer */:
450
+ return interaction.options.getInteger(arg.name, arg.required);
451
+ case "number" /* Number */:
452
+ return interaction.options.getNumber(arg.name, arg.required);
453
+ case "user" /* User */:
454
+ return interaction.options.getUser(arg.name, arg.required);
455
+ case "member" /* Member */:
456
+ return interaction.options.getMember(arg.name);
457
+ default:
458
+ return null;
459
+ }
460
+ }
461
+ };
462
+ var BaseCommandEntry = class extends BaseEntry {
463
+ constructor(options) {
464
+ super();
465
+ this.options = options;
466
+ }
467
+ }, BaseCommandGroupEntry = class extends BaseCommandEntry {
468
+ children = new Collection();
469
+ subcommand(options) {
470
+ let fullOptions = typeof options == "string" ? { name: options, description: `${options} command` } : { description: `${options.name} command`, ...options };
471
+ if (this.children.has(fullOptions.name))
472
+ throw new Error(`Entry "${fullOptions.name}" is already existed.`);
473
+ let subcommand = new SubcommandEntry(fullOptions, this);
474
+ return this.children.set(fullOptions.name, subcommand), subcommand;
475
+ }
476
+ }, RootCommandEntry = class extends BaseCommandGroupEntry {
477
+ group(options) {
478
+ let fullOptions = typeof options == "string" ? { name: options, description: `${options} command` } : { description: `${options.name} command`, ...options };
479
+ if (this.children.has(fullOptions.name))
480
+ throw new Error(`Entry "${fullOptions.name}" is already existed.`);
481
+ let group = new CommandGroupEntry(fullOptions, this);
482
+ return this.children.set(fullOptions.name, group), group;
483
+ }
484
+ }, CommandGroupEntry = class extends BaseCommandGroupEntry {
485
+ constructor(options, parent) {
486
+ super(options);
487
+ this.parent = parent;
488
+ }
489
+ }, SubcommandEntry = class extends BaseCommandEntry {
490
+ constructor(options, parent) {
491
+ super(options);
492
+ this.parent = parent;
493
+ }
494
+ };
495
+
496
+ // src/command/Command.ts
497
+ var CommandAPI;
498
+ ((CommandAPI2) => {
499
+ let rootEntries = /* @__PURE__ */ new WeakMap();
500
+ function use(root) {
501
+ return (target) => {
502
+ root.setTarget(target), rootEntries.set(target, root);
503
+ };
504
+ }
505
+ CommandAPI2.use = use;
506
+ function getRoot(constructor) {
507
+ return rootEntries.get(constructor);
508
+ }
509
+ CommandAPI2.getRoot = getRoot;
510
+ })(CommandAPI ||= {});
511
+ function CommandFactory(options) {
512
+ return typeof options == "string" && (options = { name: options }), options.description || (options.description = options.name), new RootCommandEntry(options);
513
+ }
514
+ var Command = Object.assign(CommandFactory, CommandAPI);
515
+ var CommandRegistry = class _CommandRegistry {
516
+ static constructors = new Collection();
517
+ static instances = new Collection();
518
+ /**
519
+ * Add a command to the registry.
520
+ * @param constructor The command class you want to add.
521
+ */
522
+ static add(constructor) {
523
+ let root = Command.getRoot(constructor);
524
+ if (!root)
525
+ throw new Error(`No root found for "${constructor.name}"`);
526
+ let { options } = root;
527
+ this.constructors.set(options.name, constructor), this.instances.set(options.name, new constructor());
528
+ }
529
+ /**
530
+ * Load and add all commands which matched provided glob pattern to the registry.
531
+ * @param pattern glob pattern to load.
177
532
  * @param parallel load all matched results in parallel, enabled by default.
178
533
  * @returns All loaded command constructors.
179
534
  */
@@ -319,532 +674,148 @@ var BaseContext = class {
319
674
  }
320
675
  };
321
676
 
322
- // src/utils/user.ts
323
- function extractId(value) {
324
- let idMatch = value.match(/^<@!?(\d+)>$/);
325
- if (idMatch)
326
- return idMatch[1];
327
- let numericMatch = value.match(/^(\d{17,19})$/);
328
- return numericMatch ? numericMatch[1] : null;
329
- }
677
+ // src/utils/command.ts
678
+ var defaultGetSyntaxErrorMessage = (command, error, context, resolver) => {
679
+ let requiredSyntax = resolver.args.map((x) => Arg.format(x)).join(" "), root = Command.getRoot(command.constructor);
680
+ return root ? {
681
+ content: [
682
+ codeBlock(error.message),
683
+ "Required Syntax:",
684
+ codeBlock(`${resolver.prefix}${root.options.name} ${requiredSyntax}`)
685
+ ].join(`
686
+ `)
687
+ } : void 0;
688
+ };
330
689
 
331
- // src/errors/CommandSyntaxError.ts
332
- var CommandSyntaxErrorType = /* @__PURE__ */ ((CommandSyntaxErrorType2) => (CommandSyntaxErrorType2.MissingRequireArgument = "MISSING_REQUIRE_ARGUMENT", CommandSyntaxErrorType2.InvalidArgument = "INVALID_ARGUMENT", CommandSyntaxErrorType2.InvalidVariadicArgumentValue = "INVALID_VARIADIC_ARGUMENT_VALUE", CommandSyntaxErrorType2))(CommandSyntaxErrorType || {}), CommandSyntaxError = class extends Error {
333
- arg;
334
- type;
335
- expected;
336
- received;
337
- constructor(options) {
338
- let message, { arg, type, received } = options, expected = Arg.describeArgumentExpectation(arg);
339
- switch (type) {
340
- case "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */: {
341
- message = [`Missing required argument "${arg.name}"`, `> Expected: ${expected}`].join(`
342
- `);
343
- break;
344
- }
345
- case "INVALID_ARGUMENT" /* InvalidArgument */: {
346
- message = [
347
- `Invalid value received for argument "${arg.name}"`,
348
- `> Expected: ${expected}`,
349
- `> Received: ${String(received)}`
350
- ].join(`
351
- `);
352
- break;
353
- }
354
- case "INVALID_VARIADIC_ARGUMENT_VALUE" /* InvalidVariadicArgumentValue */: {
355
- message = [
356
- `Invalid value received for variadic argument "${arg.name}"`,
357
- `> Expected: ${expected}`,
358
- `> Received: ${String(received)}`
359
- ].join(`
360
- `);
361
- break;
362
- }
363
- default: {
364
- message = "Unknown error";
365
- break;
690
+ // src/dispatchers/CommandDispatcher.ts
691
+ var CommandDispatcher = class {
692
+ constructor(client) {
693
+ this.client = client;
694
+ }
695
+ async getPrefixes(message) {
696
+ let { options, user: user2 } = this.client, results = await Promise.all(
697
+ (options.prefixes ?? []).map(async (prefix) => {
698
+ if (typeof prefix == "string")
699
+ return [prefix];
700
+ let result = await prefix(message);
701
+ return Array.isArray(result) ? result : [result];
702
+ })
703
+ ), prefixes = [...options.enableMentionPrefix && user2 ? [user2.toString()] : [], ...results.flat()];
704
+ return Array.from(new Set(prefixes));
705
+ }
706
+ async handleChatInput(interaction) {
707
+ let { commandName } = interaction, constructor = CommandRegistry.constructors.get(commandName), instance = CommandRegistry.instances.get(commandName);
708
+ if (!constructor || !instance)
709
+ return;
710
+ let root = Command.getRoot(constructor);
711
+ if (!root)
712
+ return;
713
+ let context = new ChatInputContext(interaction), triggerChain = this.getChatInputTriggerChain(interaction), chain = this.resolveCommandEntryChain(root, triggerChain), parsedValues = chain.flatMap((entry) => this.resolveChatInputEntry(interaction, entry));
714
+ await StateBox.run(() => this.executeChain(chain, context, instance, parsedValues));
715
+ }
716
+ getChatInputTriggerChain(interaction) {
717
+ let chain = [], subcommand = interaction.options.getSubcommand(false), subcommandGroup = interaction.options.getSubcommandGroup(false);
718
+ return subcommandGroup && chain.push(subcommandGroup), subcommand && chain.push(subcommand), chain;
719
+ }
720
+ resolveChatInputEntry(interaction, entry) {
721
+ let mainHook = entry.hooks.MAIN;
722
+ return (mainHook ? Arg.getMethodArguments(mainHook.method) : []).map((arg) => ArgumentResolver.resolveChatInputOption(interaction, arg));
723
+ }
724
+ async handleMessage(message) {
725
+ let resolver = await ArgumentResolver.initialize(message);
726
+ if (!resolver)
727
+ return;
728
+ let constructor = CommandRegistry.constructors.get(resolver.commandName), instance = CommandRegistry.instances.get(resolver.commandName);
729
+ if (!constructor || !instance)
730
+ return;
731
+ let root = Command.getRoot(constructor);
732
+ if (!root)
733
+ return;
734
+ let context = new MessageContext(message);
735
+ try {
736
+ await resolver.resolve(root);
737
+ } catch (error) {
738
+ if (error instanceof CommandSyntaxError) {
739
+ let payload = await this.client.options.getSyntaxErrorMessage?.(
740
+ instance,
741
+ error,
742
+ context,
743
+ resolver
744
+ );
745
+ payload && await context.send(payload);
746
+ } else
747
+ throw error;
748
+ }
749
+ let literalTriggers = resolver.args.filter((arg) => arg.type === "literal" /* Literal */).map((arg) => arg.value), entryChain = this.resolveCommandEntryChain(root, literalTriggers), values = resolver.parsedValues;
750
+ await StateBox.run(() => this.executeChain(entryChain, context, instance, values));
751
+ }
752
+ resolveCommandEntryChain(root, triggers) {
753
+ return triggers.reduce(
754
+ (acc, trigger) => {
755
+ let parent = acc.at(-1);
756
+ if (parent && "children" in parent) {
757
+ let child = parent.children.get(trigger);
758
+ child && acc.push(child);
759
+ }
760
+ return acc;
761
+ },
762
+ [root]
763
+ );
764
+ }
765
+ async executeChain(chain, context, instance, values) {
766
+ for (let entry of chain)
767
+ await this.executeHooks(entry, context, instance, values);
768
+ }
769
+ async executeHooks(entry, context, instance, values) {
770
+ let { hooks } = entry;
771
+ if (!hooks.MAIN)
772
+ return;
773
+ let execute = async (hook, error) => {
774
+ if (hook) {
775
+ if (hook.state === "ERROR" /* Error */) {
776
+ await hook.method.call(instance, error, context, ...values);
777
+ return;
778
+ }
779
+ await hook.method.call(instance, context, ...values);
366
780
  }
781
+ };
782
+ try {
783
+ await execute(hooks.PRE), await execute(hooks.MAIN), await execute(hooks.POST);
784
+ } catch (error) {
785
+ if (hooks.ERROR)
786
+ await execute(hooks.ERROR, error);
787
+ else
788
+ throw error;
367
789
  }
368
- super(message), this.arg = arg, this.type = type, this.expected = expected, this.received = received, Error.captureStackTrace(this, this.constructor);
369
790
  }
370
- get name() {
371
- return `CommandSyntaxError[${this.type}]`;
791
+ };
792
+
793
+ // src/dispatchers/DispatcherManager.ts
794
+ var DispatcherManager = class {
795
+ constructor(client) {
796
+ this.client = client;
797
+ this.command = new CommandDispatcher(client);
372
798
  }
799
+ command;
373
800
  };
374
801
 
375
- // src/command/argument/ArgumentResolver.ts
376
- var ArgumentResolver = class _ArgumentResolver {
802
+ // src/BakitClient.ts
803
+ var BakitClient = class extends Client {
804
+ dispatchers;
377
805
  constructor(options) {
378
- this.options = options;
379
- }
380
- parsedValues = [];
381
- /**
382
- * Get the first value as the command trigger.
383
- */
384
- get trigger() {
385
- return this.options.values[0];
386
- }
387
- /**
388
- * Get amount of specified argument values.
389
- */
390
- get specifiedAmount() {
391
- return this.options.values.length - this.options.startAt;
806
+ options.getSyntaxErrorMessage === void 0 && (options.getSyntaxErrorMessage = defaultGetSyntaxErrorMessage), super(options), ListenerRegistry.setClient(this), this.dispatchers = new DispatcherManager(this), this.initializeHandlers();
392
807
  }
393
- /**
394
- * Get parsed raw values from content.
395
- */
396
- get values() {
397
- return [...this.options.values];
808
+ isReady() {
809
+ return super.isReady();
398
810
  }
399
- get client() {
400
- return this.options.message.client;
401
- }
402
- static create(message) {
403
- let client = message.client, { enableMentionPrefix } = client.options, prefix = [
404
- // Custom prefixes specified in options
405
- ...client.options.prefixes ?? [],
406
- // Use bot mention as prefix if enabled
407
- ...enableMentionPrefix ? [client.user.toString()] : []
408
- ].find((p) => message.content.startsWith(p)) ?? null;
409
- if (!prefix)
410
- return;
411
- let values = message.content.slice(prefix.length).trim().split(/\s+/);
412
- return new _ArgumentResolver({
413
- message,
414
- startAt: 1,
415
- // Skip the command trigger
416
- values,
417
- args: [],
418
- prefix
419
- });
420
- }
421
- async resolve(args) {
422
- let child = new _ArgumentResolver({
423
- prefix: this.options.prefix,
424
- message: this.options.message,
425
- values: this.options.values,
426
- args,
427
- startAt: this.options.startAt
811
+ initializeHandlers() {
812
+ this.on(
813
+ Events.MessageCreate,
814
+ (message) => void this.dispatchers.command.handleMessage(message)
815
+ ), this.on(Events.InteractionCreate, (interaction) => {
816
+ interaction.isChatInputCommand() && this.dispatchers.command.handleChatInput(interaction);
428
817
  });
429
- return child.parsedValues = [...this.parsedValues], child.options.args.length && (this.specifiedAmount >= child.options.args.length ? await child.absoluteParse() : await child.dynamicParse()), child;
430
- }
431
- async absoluteParse() {
432
- let { args, values, startAt } = this.options, valueIndex = startAt, argIndex = 0;
433
- for (; valueIndex < values.length && argIndex < args.length; ) {
434
- let value = values[valueIndex], arg = args[argIndex];
435
- if (arg.tuple) {
436
- this.parsedValues.push(...await this.resolveTuple(arg, valueIndex, argIndex));
437
- break;
438
- }
439
- let matchedValue = await this.matchValue(arg, value);
440
- if (matchedValue === null)
441
- throw new CommandSyntaxError({
442
- arg,
443
- type: "INVALID_ARGUMENT" /* InvalidArgument */,
444
- received: value
445
- });
446
- this.parsedValues.push(matchedValue), valueIndex++, argIndex++;
447
- }
448
- }
449
- async dynamicParse() {
450
- let { args, values } = this.options, argIndex = 0, valueIndex = this.options.startAt + 1;
451
- for (; valueIndex < values.length && argIndex < args.length; ) {
452
- let value = values[valueIndex], arg = args[argIndex];
453
- if (arg.tuple) {
454
- this.parsedValues.push(...await this.resolveTuple(arg, valueIndex, argIndex));
455
- break;
456
- }
457
- let matchedValue = await this.matchValue(arg, value);
458
- if (matchedValue !== null)
459
- this.parsedValues.push(matchedValue), valueIndex++;
460
- else if (arg.required)
461
- throw new CommandSyntaxError({
462
- arg,
463
- type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
464
- received: value
465
- });
466
- argIndex++;
467
- }
468
- for (; argIndex < args.length; ) {
469
- let arg = args[argIndex];
470
- if (arg.required)
471
- throw new CommandSyntaxError({
472
- arg,
473
- type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
474
- received: "nothing"
475
- });
476
- argIndex++;
477
- }
478
- }
479
- async resolveTuple(arg, startIndex, argIndex) {
480
- let { args } = this.options;
481
- if (argIndex !== args.length - 1)
482
- throw new SyntaxError("Tuple argument must be the last argument");
483
- let values = [];
484
- for (let rest of this.values.slice(startIndex)) {
485
- let matchedValue = await this.matchValue(arg, rest);
486
- if (matchedValue === null)
487
- throw new CommandSyntaxError({
488
- arg,
489
- type: "INVALID_VARIADIC_ARGUMENT_VALUE" /* InvalidVariadicArgumentValue */,
490
- received: rest
491
- });
492
- values.push(matchedValue);
493
- }
494
- if (values.length === 0 && arg.required)
495
- throw new CommandSyntaxError({
496
- arg,
497
- type: "MISSING_REQUIRE_ARGUMENT" /* MissingRequireArgument */,
498
- received: "nothing"
499
- });
500
- return values;
501
- }
502
- async matchValue(arg, value) {
503
- switch (arg.type) {
504
- case "user" /* User */:
505
- return await this.matchUserValue(arg, value);
506
- case "integer" /* Integer */:
507
- return this.matchIntegerValue(arg, value);
508
- case "number" /* Number */:
509
- return this.matchNumberValue(arg, value);
510
- case "string" /* String */:
511
- return this.matchStringValue(arg, value);
512
- default:
513
- return null;
514
- }
515
- }
516
- async matchUserValue(arg, value) {
517
- let userId = extractId(value);
518
- if (!userId)
519
- return null;
520
- let user2 = await this.client.users.fetch(userId).catch(() => null);
521
- return user2 || null;
522
- }
523
- matchIntegerValue(arg, value) {
524
- let intVal = parseInt(value, 10);
525
- return isNaN(intVal) || arg.minValue !== void 0 && intVal < arg.minValue || arg.maxValue !== void 0 && intVal > arg.maxValue ? null : intVal;
526
- }
527
- matchNumberValue(arg, value) {
528
- let numVal = parseFloat(value);
529
- return isNaN(numVal) || arg.minValue !== void 0 && numVal < arg.minValue || arg.maxValue !== void 0 && numVal > arg.maxValue ? null : numVal;
530
- }
531
- matchStringValue(arg, value) {
532
- return arg.minLength !== void 0 && value.length < arg.minLength || arg.maxLength !== void 0 && value.length > arg.maxLength ? null : value;
533
- }
534
- static resolveChatInput(interaction, arg) {
535
- switch (arg.type) {
536
- case "string" /* String */:
537
- return interaction.options.getString(arg.name, arg.required);
538
- case "integer" /* Integer */:
539
- return interaction.options.getInteger(arg.name, arg.required);
540
- case "number" /* Number */:
541
- return interaction.options.getNumber(arg.name, arg.required);
542
- case "user" /* User */:
543
- return interaction.options.getUser(arg.name, arg.required);
544
- case "member" /* Member */:
545
- return interaction.options.getMember(arg.name);
546
- default:
547
- return null;
548
- }
549
- }
550
- };
551
- var StateBox = class _StateBox {
552
- static STATES_KEY = Symbol("states");
553
- static storage = new AsyncLocalStorage();
554
- static getState() {
555
- let state = this.storage.getStore();
556
- if (!state)
557
- throw new Error("No active context, did you forget to wrap it with StateBox.wrap()?");
558
- return state;
559
- }
560
- static run(fn, store2 = {}) {
561
- return this.storage.run(store2, fn);
562
- }
563
- static wrap(fn) {
564
- let currentStore = this.storage.getStore();
565
- if (!currentStore)
566
- throw new Error("No active context, cannot wrap function outside a StateBox.run()");
567
- return () => this.run(fn, currentStore);
568
- }
569
- static use(defaultValue) {
570
- return (target, key) => {
571
- Object.defineProperty(target, key, {
572
- get() {
573
- let states = _StateBox.getState();
574
- return key in states || (states[key] = defaultValue), states[key];
575
- },
576
- set(value) {
577
- let states = _StateBox.getState();
578
- states[key] = value;
579
- },
580
- enumerable: true,
581
- configurable: true
582
- });
583
- };
584
- }
585
- };
586
-
587
- // src/listener/ListenerEntry.ts
588
- var ListenerEntry = class extends BaseEntry {
589
- constructor(options) {
590
- super();
591
- this.options = options;
592
- }
593
- };
594
-
595
- // src/listener/Listener.ts
596
- var ListenerAPI;
597
- ((ListenerAPI2) => {
598
- let entries = /* @__PURE__ */ new WeakMap();
599
- function use(entry) {
600
- return (target) => {
601
- entries.set(target, entry);
602
- };
603
- }
604
- ListenerAPI2.use = use;
605
- function getEntry(target) {
606
- return entries.get(target);
607
- }
608
- ListenerAPI2.getEntry = getEntry;
609
- })(ListenerAPI ||= {});
610
- function ListenerFactory(options) {
611
- let fullOptions = typeof options != "object" ? { name: options, once: false } : { once: false, ...options };
612
- return new ListenerEntry(fullOptions);
613
- }
614
- var Listener = Object.assign(ListenerFactory, ListenerAPI);
615
- var ListenerRegistry = class {
616
- static client;
617
- static constructors = /* @__PURE__ */ new Set();
618
- static instances = /* @__PURE__ */ new WeakMap();
619
- static executors = /* @__PURE__ */ new WeakMap();
620
- /**
621
- * Add and register a listener to the registry.
622
- * If `options.emitter` is not provided, the registry will use the base `client` by default.
623
- * @param constructor The listener class you want to add.
624
- */
625
- static add(constructor) {
626
- let entry = Listener.getEntry(constructor);
627
- if (!entry)
628
- throw new Error(`No entry found for "${constructor.name}"`);
629
- let { options } = entry;
630
- if (!options.emitter) {
631
- if (!this.client)
632
- throw new Error("Client is not ready.");
633
- options.emitter = this.client;
634
- }
635
- let instance = new constructor(), executor = this.createExecutor(constructor, instance);
636
- this.constructors.add(constructor), this.instances.set(constructor, instance), this.executors.set(instance, executor), options.emitter[options.once ? "once" : "on"](options.name, (...args) => {
637
- executor(...args);
638
- });
639
- }
640
- /**
641
- * Remove and unregister a listener from the registry.
642
- * @param constructor The listener class you want to remove.
643
- * @returns `boolean`, returns `true` if the listener is removed successfully.
644
- */
645
- static remove(constructor) {
646
- let entry = Listener.getEntry(constructor);
647
- if (!entry)
648
- return false;
649
- this.constructors.delete(constructor);
650
- let instance = this.instances.get(constructor);
651
- if (!instance)
652
- return false;
653
- this.instances.delete(constructor);
654
- let executor = this.executors.get(instance);
655
- if (!executor)
656
- return false;
657
- let { name, emitter } = entry.options;
658
- return emitter?.removeListener(name, executor), this.executors.delete(instance), true;
659
- }
660
- /**
661
- * Remove and unregister all listeners from the registry.
662
- * @returns Amount of removed listeners.
663
- */
664
- static removeAll() {
665
- let removedAmount = 0;
666
- for (let constructor of this.constructors)
667
- this.remove(constructor) && removedAmount++;
668
- return removedAmount;
669
- }
670
- /**
671
- * Set base client for the registry to fallback as default emitter. This should be used only by BakitClient and stay untouched.
672
- * @param newClient base client to set for the registry.
673
- */
674
- static setClient(newClient) {
675
- this.client = newClient;
676
- }
677
- static createExecutor(constructor, instance) {
678
- let entry = Listener.getEntry(constructor);
679
- if (!entry)
680
- throw new Error("Missing listener entry");
681
- let { hooks } = entry;
682
- return async function(...args) {
683
- let mainHook = hooks.MAIN, preHook = hooks.PRE, postHook = hooks.POST, errorHook = hooks.ERROR;
684
- if (mainHook)
685
- try {
686
- preHook && await preHook.method.call(instance, ...args), await mainHook.method.call(instance, ...args), postHook && await postHook.method.call(instance, ...args);
687
- } catch (error) {
688
- if (errorHook)
689
- await errorHook.method.call(
690
- instance,
691
- error,
692
- ...args
693
- );
694
- else
695
- throw error;
696
- }
697
- };
698
- }
699
- /**
700
- * Load and add all listeners which matched provided glob pattern to the registry.
701
- * @param pattern glob pattern to load.
702
- * @param parallel load all matched results in parallel, enabled by default.
703
- * @returns All loaded listener constructors.
704
- */
705
- static async load(pattern, parallel = true) {
706
- let loaders = (await glob(pattern)).map(async (file) => {
707
- let fileURL = pathToFileURL(file).toString(), { default: constructor } = await import(fileURL);
708
- return this.add(constructor), constructor;
709
- });
710
- if (parallel)
711
- return Promise.all(loaders);
712
- let result = [];
713
- for (let loader of loaders)
714
- result.push(await loader);
715
- return result;
716
- }
717
- };
718
-
719
- // src/BakitClient.ts
720
- var BakitClient = class _BakitClient extends Client {
721
- constructor(options) {
722
- options.getSyntaxErrorMessage === void 0 && (options.getSyntaxErrorMessage = _BakitClient.getSyntaxErrorMessage), super(options), ListenerRegistry.setClient(this), this.once(
723
- Events.ClientReady,
724
- (client) => void this.registerApplicationCommands(client)
725
- ), this.on(Events.InteractionCreate, (interaction) => void this.handleInteraction(interaction)), this.on(Events.MessageCreate, (message) => void this.handleMessage(message));
726
- }
727
- static getSyntaxErrorMessage = (command, error, context, args, prefix) => {
728
- let requiredSyntax = args.map((x) => Arg.format(x)).join(" "), root = Command.getRoot(command.constructor);
729
- return root ? {
730
- content: [
731
- codeBlock(error.message),
732
- "Required Syntax:",
733
- codeBlock(`${prefix}${root.options.name} ${requiredSyntax}`)
734
- ].join(`
735
- `)
736
- } : void 0;
737
- };
738
- async registerApplicationCommands(client) {
739
- let commands = CommandRegistry.constructors.map((c) => CommandRegistry.buildSlashCommand(c));
740
- await client.application.commands.set(commands);
741
- }
742
- async handleMessage(message) {
743
- if (message.author.bot)
744
- return;
745
- let context = new MessageContext(message), resolver = ArgumentResolver.create(message);
746
- if (!resolver)
747
- return;
748
- let { trigger } = resolver, command = CommandRegistry.instances.get(trigger);
749
- command && await StateBox.run(() => this.handleMessageHooks(context, command, resolver));
750
- }
751
- async handleInteraction(interaction) {
752
- if (!interaction.isChatInputCommand())
753
- return;
754
- let { commandName } = interaction, command = CommandRegistry.instances.get(commandName);
755
- if (!command)
756
- return;
757
- let context = new ChatInputContext(interaction);
758
- await StateBox.run(() => this.handleChatInputHooks(context, command));
759
- }
760
- async handleChatInputHooks(context, instance) {
761
- let targetHooks = this.getChatInputTargetHooks(context.source, instance), inheritedArgs = [];
762
- for (let hooks of [targetHooks.root, targetHooks.group, targetHooks.subcommand]) {
763
- if (!hooks)
764
- continue;
765
- let newArgs = await this.runChatInputHooks(context, instance, hooks, inheritedArgs);
766
- newArgs && (inheritedArgs = newArgs);
767
- }
768
- }
769
- async handleMessageHooks(context, instance, resolver) {
770
- if (!resolver)
771
- return;
772
- let root = Command.getRoot(instance.constructor);
773
- root && (resolver = await this.runMessageHooks(context, instance, root.hooks, resolver), resolver && await this.handleChildMessageHooks(context, root, instance, resolver));
774
- }
775
- async handleChildMessageHooks(context, parent, instance, resolver, skip = 1) {
776
- if (!resolver)
777
- return;
778
- let usedValues = resolver.parsedValues.length, nextTrigger = resolver.values[usedValues + skip], child = parent.children.get(nextTrigger);
779
- child && (resolver = await this.runMessageHooks(context, instance, child.hooks, resolver), child instanceof CommandGroupEntry && await this.handleChildMessageHooks(context, child, instance, resolver, skip + 1));
780
- }
781
- async runMessageHooks(context, instance, hooks, resolver) {
782
- let mainHook = hooks.MAIN;
783
- if (!mainHook)
784
- return resolver;
785
- let args = Arg.getMethodArguments(mainHook.method);
786
- try {
787
- resolver = await resolver.resolve(args);
788
- } catch (error) {
789
- if (error instanceof CommandSyntaxError) {
790
- let errorContent = await this.options.getSyntaxErrorMessage?.(
791
- instance,
792
- error,
793
- context,
794
- args,
795
- resolver.options.prefix
796
- );
797
- return errorContent && await context.send(errorContent), null;
798
- }
799
- throw error;
800
- }
801
- return await this.runHooks(context, instance, hooks, resolver.parsedValues), resolver;
802
- }
803
- async runChatInputHooks(context, instance, hooks, inheritedArgs) {
804
- let mainHook = hooks.MAIN;
805
- if (!mainHook)
806
- return;
807
- let newArgs = Arg.getMethodArguments(mainHook.method).map(
808
- (arg) => ArgumentResolver.resolveChatInput(context.source, arg)
809
- ), argValues = [...inheritedArgs, ...newArgs];
810
- return await this.runHooks(context, instance, hooks, argValues), argValues;
811
- }
812
- async runHooks(context, instance, hooks, args) {
813
- let mainHook = hooks.MAIN, preHook = hooks.PRE, postHook = hooks.POST, errorHook = hooks.ERROR;
814
- if (!mainHook)
815
- return;
816
- let execute = async (hook, error) => {
817
- hook && (hook.state === "ERROR" /* Error */ ? await hook.method.call(instance, error, context, ...args) : await hook.method.call(instance, context, ...args));
818
- };
819
- try {
820
- await execute(preHook), await execute(mainHook), await execute(postHook);
821
- } catch (error) {
822
- if (errorHook)
823
- await execute(errorHook, error);
824
- else
825
- throw error;
826
- }
827
- }
828
- getChatInputTargetHooks(interaction, instance) {
829
- let subcommandName = interaction.options.getSubcommand(false), groupName = interaction.options.getSubcommandGroup(false), root = Command.getRoot(instance.constructor);
830
- if (!root)
831
- throw new Error("No root found.");
832
- let group;
833
- if (groupName) {
834
- let child = root.children.get(groupName);
835
- child instanceof CommandGroupEntry && (group = child);
836
- }
837
- let subcommand;
838
- if (subcommandName) {
839
- let child = (group || root).children.get(subcommandName);
840
- child instanceof SubcommandEntry && (subcommand = child);
841
- }
842
- return {
843
- root: root.hooks,
844
- group: group?.hooks,
845
- subcommand: subcommand?.hooks
846
- };
847
818
  }
848
819
  };
849
820
 
850
- export { Arg, ArgumentType, BakitClient, BaseCommandEntry, BaseCommandGroupEntry, BaseContext, ChatInputContext, Command, CommandAPI, CommandFactory, CommandGroupEntry, CommandRegistry, CommandSyntaxError, CommandSyntaxErrorType, Listener, ListenerAPI, ListenerEntry, ListenerFactory, ListenerRegistry, MessageContext, RootCommandEntry, StateBox, SubcommandEntry, extractId };
821
+ export { Arg, ArgumentResolver, ArgumentType, BakitClient, BaseCommandEntry, BaseCommandGroupEntry, BaseContext, ChatInputContext, Command, CommandAPI, CommandFactory, CommandGroupEntry, CommandRegistry, CommandSyntaxError, CommandSyntaxErrorType, Listener, ListenerAPI, ListenerEntry, ListenerFactory, ListenerRegistry, MessageContext, RootCommandEntry, StateBox, SubcommandEntry, defaultGetSyntaxErrorMessage, extractId };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bakit",
3
- "version": "1.0.0-beta.14",
3
+ "version": "1.0.0-beta.16",
4
4
  "description": "A framework for discord.js",
5
5
  "type": "module",
6
6
  "exports": {