bakit 1.0.0-beta.5 → 1.0.0-beta.7

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.
package/dist/index.js CHANGED
@@ -18,6 +18,125 @@ import { pathToFileURL } from "url";
18
18
  // src/command/CommandEntry.ts
19
19
  import { Collection } from "discord.js";
20
20
 
21
+ // src/base/BaseEntry.ts
22
+ var BaseEntry = class {
23
+ target;
24
+ hooks = {
25
+ ["MAIN" /* Main */]: void 0,
26
+ ["ERROR" /* Error */]: void 0,
27
+ ["POST" /* Post */]: void 0,
28
+ ["PRE" /* Pre */]: void 0
29
+ };
30
+ main;
31
+ pre;
32
+ post;
33
+ error;
34
+ constructor() {
35
+ this.main = this.createMainHookDecorator("MAIN" /* Main */);
36
+ this.pre = this.createMainHookDecorator("PRE" /* Pre */);
37
+ this.post = this.createMainHookDecorator("POST" /* Post */);
38
+ this.error = this.createMainHookDecorator("ERROR" /* Error */);
39
+ }
40
+ setTarget(target) {
41
+ this.target = target;
42
+ }
43
+ createMainHookDecorator(state) {
44
+ return (target, _key, descriptor) => {
45
+ this.addHook(state, target, descriptor);
46
+ };
47
+ }
48
+ createErrorHookDecorator(state) {
49
+ return (target, _key, descriptor) => {
50
+ this.addHook(state, target, descriptor);
51
+ };
52
+ }
53
+ addHook(state, target, descriptor) {
54
+ if (target.constructor !== this.target) {
55
+ throw new Error("Hook is used at unknown constructor.");
56
+ }
57
+ const { value: method } = descriptor;
58
+ if (typeof method !== "function") {
59
+ throw new Error("Invalid target method for hook.");
60
+ }
61
+ const hook = {
62
+ state,
63
+ method,
64
+ entry: this
65
+ };
66
+ this.hooks[state] = hook;
67
+ }
68
+ };
69
+
70
+ // src/command/CommandEntry.ts
71
+ var BaseCommandEntry = class extends BaseEntry {
72
+ constructor(options) {
73
+ super();
74
+ this.options = options;
75
+ }
76
+ };
77
+ var BaseCommandGroupEntry = class extends BaseCommandEntry {
78
+ children = new Collection();
79
+ subcommand(options) {
80
+ const fullOptions = typeof options === "string" ? { name: options, description: `${options} command` } : { description: `${options.name} command`, ...options };
81
+ if (this.children.has(fullOptions.name)) {
82
+ throw new Error(`Entry "${fullOptions.name}" is already existed.`);
83
+ }
84
+ const subcommand = new SubcommandEntry(fullOptions, this);
85
+ this.children.set(fullOptions.name, subcommand);
86
+ return subcommand;
87
+ }
88
+ };
89
+ var RootCommandEntry = class extends BaseCommandGroupEntry {
90
+ group(options) {
91
+ const fullOptions = typeof options === "string" ? { name: options, description: `${options} command` } : { description: `${options.name} command`, ...options };
92
+ if (this.children.has(fullOptions.name)) {
93
+ throw new Error(`Entry "${fullOptions.name}" is already existed.`);
94
+ }
95
+ const group = new CommandGroupEntry(fullOptions, this);
96
+ this.children.set(fullOptions.name, group);
97
+ return group;
98
+ }
99
+ };
100
+ var CommandGroupEntry = class extends BaseCommandGroupEntry {
101
+ constructor(options, parent) {
102
+ super(options);
103
+ this.parent = parent;
104
+ }
105
+ };
106
+ var SubcommandEntry = class extends BaseCommandEntry {
107
+ constructor(options, parent) {
108
+ super(options);
109
+ this.parent = parent;
110
+ }
111
+ };
112
+
113
+ // src/command/Command.ts
114
+ var CommandAPI;
115
+ ((CommandAPI2) => {
116
+ const ROOT_KEY = Symbol("root");
117
+ function use(command) {
118
+ return (target) => {
119
+ command.setTarget(target);
120
+ Reflect.defineMetadata(ROOT_KEY, command, target);
121
+ };
122
+ }
123
+ CommandAPI2.use = use;
124
+ function getRoot(constructor) {
125
+ return Reflect.getMetadata(ROOT_KEY, constructor);
126
+ }
127
+ CommandAPI2.getRoot = getRoot;
128
+ })(CommandAPI || (CommandAPI = {}));
129
+ function CommandFactory(options) {
130
+ if (typeof options === "string") {
131
+ options = { name: options };
132
+ }
133
+ if (!options.description) {
134
+ options.description = options.name;
135
+ }
136
+ return new RootCommandEntry(options);
137
+ }
138
+ var Command = Object.assign(CommandFactory, CommandAPI);
139
+
21
140
  // src/command/argument/Argument.ts
22
141
  var ArgumentType = /* @__PURE__ */ ((ArgumentType2) => {
23
142
  ArgumentType2["String"] = "string";
@@ -121,157 +240,14 @@ var Arg = {
121
240
  member
122
241
  };
123
242
 
124
- // src/command/CommandEntry.ts
125
- var CommandHookExecutionState = /* @__PURE__ */ ((CommandHookExecutionState2) => {
126
- CommandHookExecutionState2["Main"] = "main";
127
- CommandHookExecutionState2["Pre"] = "pre";
128
- CommandHookExecutionState2["Post"] = "post";
129
- CommandHookExecutionState2["Error"] = "error";
130
- return CommandHookExecutionState2;
131
- })(CommandHookExecutionState || {});
132
- var HOOKS_KEY = Symbol("hooks");
133
- var BaseCommandEntry = class _BaseCommandEntry {
134
- constructor(options) {
135
- this.options = options;
136
- }
137
- static cache = /* @__PURE__ */ new WeakMap();
138
- main = _BaseCommandEntry.createMainHookDecorator("main" /* Main */, this);
139
- pre = _BaseCommandEntry.createMainHookDecorator("pre" /* Pre */, this);
140
- post = _BaseCommandEntry.createMainHookDecorator("post" /* Post */, this);
141
- error = _BaseCommandEntry.createErrorHookDecorator("error" /* Error */, this);
142
- static getHooks(constructor, init = false) {
143
- let hooks = this.cache.get(constructor) ?? Reflect.getMetadata(HOOKS_KEY, constructor);
144
- if (!hooks) {
145
- hooks = [];
146
- if (init) {
147
- Reflect.defineMetadata(HOOKS_KEY, hooks, constructor);
148
- this.cache.set(constructor, hooks);
149
- }
150
- }
151
- return init ? hooks : Object.freeze([...hooks]);
152
- }
153
- static createMainHookDecorator(state, entry) {
154
- return (target, _key, descriptor) => {
155
- this.addHook(target, state, descriptor.value, entry);
156
- };
157
- }
158
- static createErrorHookDecorator(state, entry) {
159
- return (target, _key, descriptor) => {
160
- this.addHook(target, state, descriptor.value, entry);
161
- };
162
- }
163
- static addHook(target, state, method, entry) {
164
- const { constructor } = target;
165
- const hooks = _BaseCommandEntry.getHooks(constructor, true);
166
- if (typeof method !== "function") {
167
- throw new Error("CommandEntry decorator must be used with a class method.");
168
- }
169
- if (hooks.some((hook) => hook.state === state && hook.entry === entry)) {
170
- throw new Error(`Hook "${state}" is already defined for entry "${entry.options.name}".`);
171
- }
172
- if ("parent" in entry) {
173
- const parentHook = hooks.find(
174
- (hook) => hook.entry === entry.parent && hook.state === "main" /* Main */
175
- );
176
- if (parentHook) {
177
- const parentArgs = Arg.getMethodArguments(parentHook.method);
178
- if (parentArgs.at(-1)?.tuple) {
179
- throw new Error(
180
- `Cannot add hook "${state}" to entry "${entry.options.name}" because its parent "${entry.parent.options.name}" has a tuple argument.`
181
- );
182
- }
183
- }
184
- }
185
- hooks.push({
186
- state,
187
- entry,
188
- method
189
- });
190
- }
191
- };
192
- var BaseCommandGroupEntry = class extends BaseCommandEntry {
193
- children = new Collection();
194
- subcommand(options) {
195
- if (typeof options === "string") {
196
- options = { name: options };
197
- }
198
- if (!options.description) {
199
- options.description = options.name;
200
- }
201
- if (this.children.has(options.name)) {
202
- throw new Error(`Entry with name "${options.name}" already exists.`);
203
- }
204
- if (!(this instanceof CommandGroupEntry) && !(this instanceof RootCommandEntry)) {
205
- throw new Error(`Invalid parent "${this.constructor.name}"`);
206
- }
207
- const entry = new SubcommandEntry(options, this);
208
- this.children.set(entry.options.name, entry);
209
- return entry;
210
- }
211
- };
212
- var CommandGroupEntry = class extends BaseCommandGroupEntry {
213
- constructor(options, parent) {
214
- super(options);
215
- this.options = options;
216
- this.parent = parent;
217
- }
218
- };
219
- var RootCommandEntry = class extends BaseCommandGroupEntry {
220
- constructor(options) {
221
- super(options);
222
- this.options = options;
223
- }
224
- group(options) {
225
- if (typeof options === "string") {
226
- options = { name: options };
227
- }
228
- if (!options.description) {
229
- options.description = options.name;
230
- }
231
- if (this.children.has(options.name)) {
232
- throw new Error(`Entry with name "${options.name}" already exists.`);
233
- }
234
- const entry = new CommandGroupEntry(options, this);
235
- this.children.set(entry.options.name, entry);
236
- return entry;
237
- }
238
- };
239
- var SubcommandEntry = class extends BaseCommandEntry {
240
- constructor(options, parent) {
241
- super(options);
242
- this.options = options;
243
- this.parent = parent;
244
- }
245
- };
246
-
247
- // src/command/Command.ts
248
- var ROOT_KEY = Symbol("root");
249
- function use(command) {
250
- return (target) => {
251
- Reflect.defineMetadata(ROOT_KEY, command, target);
252
- };
253
- }
254
- function getRoot(constructor) {
255
- return Reflect.getMetadata(ROOT_KEY, constructor);
256
- }
257
- function CommandFactory(options) {
258
- if (typeof options === "string") {
259
- options = { name: options };
260
- }
261
- if (!options.description) {
262
- options.description = options.name;
263
- }
264
- return new RootCommandEntry(options);
265
- }
266
- var Command = Object.assign(CommandFactory, {
267
- use,
268
- getRoot
269
- });
270
-
271
243
  // src/command/CommandRegistry.ts
272
244
  var CommandRegistry = class _CommandRegistry {
273
245
  static constructors = new Collection2();
274
246
  static instances = new Collection2();
247
+ /**
248
+ * Add a command to the registry.
249
+ * @param constructor The command class you want to add.
250
+ */
275
251
  static add(constructor) {
276
252
  const root = Command.getRoot(constructor);
277
253
  if (!root) {
@@ -281,20 +257,13 @@ var CommandRegistry = class _CommandRegistry {
281
257
  this.constructors.set(options.name, constructor);
282
258
  this.instances.set(options.name, new constructor());
283
259
  }
284
- static buildSlashCommand(constructor) {
285
- const builder = new SlashCommandBuilder();
286
- const root = Command.getRoot(constructor);
287
- if (!root) {
288
- throw new Error(`No root found for "${constructor.name}"`);
289
- }
290
- const { options } = root;
291
- builder.setName(options.name);
292
- builder.setDescription(options.description || "");
293
- builder.setNSFW(Boolean(options.nsfw));
294
- this.buildSlashCommandOptions(builder, constructor);
295
- return builder.toJSON();
296
- }
297
- static async loadDirectory(pattern, parallel = true) {
260
+ /**
261
+ * Load and add all commands which matched provided glob pattern to the registry.
262
+ * @param pattern glob pattern to load.
263
+ * @param parallel load all matched results in parallel, enabled by default.
264
+ * @returns All loaded command constructors.
265
+ */
266
+ static async load(pattern, parallel = true) {
298
267
  const files = await glob(pattern);
299
268
  const loaders = files.map(async (file) => {
300
269
  const fileURL = pathToFileURL(file).toString();
@@ -311,72 +280,102 @@ var CommandRegistry = class _CommandRegistry {
311
280
  }
312
281
  return result;
313
282
  }
314
- static buildSlashCommandOptions(builder, constructor) {
283
+ /**
284
+ * Build a command into application command data.
285
+ * @param constructor The command class you want to build.
286
+ * @returns a REST JSON version of the application command data.
287
+ */
288
+ static buildSlashCommand(constructor) {
315
289
  const root = Command.getRoot(constructor);
316
290
  if (!root) {
317
291
  throw new Error(`No root found for "${constructor.name}"`);
318
292
  }
319
- const hooks = new Collection2(
320
- BaseCommandEntry.getHooks(constructor).filter((hook) => hook.state === "main" /* Main */).map((hook) => [hook.entry, hook])
321
- );
322
- const rootHook = hooks.get(root);
323
- if (!root.children.size && hooks.size) {
324
- if (!rootHook) {
325
- return;
326
- }
327
- for (const arg of Arg.getMethodArguments(rootHook.method)) {
328
- this.buildSlashCommandOption(builder, arg);
329
- }
330
- return;
293
+ const { options } = root;
294
+ const builder = new SlashCommandBuilder().setName(options.name).setDescription(options.description).setNSFW(Boolean(options.nsfw));
295
+ const args = this.getMainHookArguments(root);
296
+ if (root.children.size) {
297
+ this.buildSlashCommandSubcommands(builder, root, args);
298
+ } else {
299
+ this.buildSlashCommandOptions(builder, args);
331
300
  }
332
- for (const child of root.children.values()) {
333
- const hook = hooks.get(child);
334
- const inheritedArgs = [];
335
- if (rootHook) {
336
- inheritedArgs.push(...Arg.getMethodArguments(rootHook.method));
337
- }
338
- if (child instanceof SubcommandEntry) {
339
- this.buildSubcommand(builder, child, hook, inheritedArgs);
340
- } else if (child instanceof CommandGroupEntry) {
341
- if (hook) {
342
- inheritedArgs.push(...Arg.getMethodArguments(hook.method));
343
- }
301
+ return builder.toJSON();
302
+ }
303
+ static getMainHookArguments(entry) {
304
+ const { hooks } = entry;
305
+ const mainHook = hooks["MAIN" /* Main */];
306
+ return mainHook ? Arg.getMethodArguments(mainHook.method) : [];
307
+ }
308
+ static buildSlashCommandSubcommands(parent, entry, inheritedArgs) {
309
+ const { children } = entry;
310
+ for (const child of children.values()) {
311
+ if (child instanceof CommandGroupEntry && parent instanceof SlashCommandBuilder) {
344
312
  const { options } = child;
345
313
  const group = new SlashCommandSubcommandGroupBuilder().setName(options.name).setDescription(options.description);
346
- for (const subChild of child.children.values()) {
347
- this.buildSubcommand(group, subChild, hooks.get(subChild), inheritedArgs);
348
- }
349
- builder.addSubcommandGroup(group);
314
+ this.buildSlashCommandSubcommands(group, child, [
315
+ ...inheritedArgs,
316
+ ...this.getMainHookArguments(child)
317
+ ]);
318
+ parent.addSubcommandGroup(group);
319
+ } else if (child instanceof SubcommandEntry) {
320
+ const { options } = child;
321
+ const subcommand = new SlashCommandSubcommandBuilder().setName(options.name).setDescription(options.description);
322
+ this.buildSlashCommandOptions(subcommand, [
323
+ ...inheritedArgs,
324
+ ...this.getMainHookArguments(child)
325
+ ]);
326
+ parent.addSubcommand(subcommand);
350
327
  }
351
328
  }
352
329
  }
353
- static buildSubcommand(parent, entry, hook, inheritedArgs) {
354
- const { options } = entry;
355
- const subcommand = new SlashCommandSubcommandBuilder().setName(options.name).setDescription(options.description);
356
- const args = [...inheritedArgs];
357
- if (hook) {
358
- args.push(...Arg.getMethodArguments(hook.method));
359
- }
360
- for (const arg of args) {
361
- this.buildSlashCommandOption(subcommand, arg);
330
+ static buildSlashCommandOptions(builder, args) {
331
+ const argGroup = Object.groupBy(args, ({ required }) => required ? "required" : "optional");
332
+ const orderedArgs = [...argGroup.required || [], ...argGroup.optional || []];
333
+ for (const arg of orderedArgs) {
334
+ this.attachSlashCommandOption(builder, arg);
362
335
  }
363
- parent.addSubcommand(subcommand);
364
336
  }
365
- static buildSlashCommandOption(builder, arg) {
337
+ static attachSlashCommandOption(builder, arg) {
366
338
  const setupOption = (option) => {
367
339
  return option.setName(arg.name).setDescription(arg.description || arg.name).setRequired(Boolean(arg.required));
368
340
  };
369
341
  switch (arg.type) {
370
342
  case "string" /* String */: {
371
- builder.addStringOption((option) => setupOption(option));
343
+ builder.addStringOption((data) => {
344
+ const option = setupOption(data);
345
+ if (arg.maxLength) {
346
+ option.setMaxLength(arg.maxLength);
347
+ }
348
+ if (arg.minLength) {
349
+ option.setMinLength(arg.minLength);
350
+ }
351
+ return option;
352
+ });
372
353
  break;
373
354
  }
374
355
  case "integer" /* Integer */: {
375
- builder.addIntegerOption((option) => setupOption(option));
356
+ builder.addIntegerOption((data) => {
357
+ const option = setupOption(data);
358
+ if (arg.maxValue) {
359
+ option.setMaxValue(arg.maxValue);
360
+ }
361
+ if (arg.minValue) {
362
+ option.setMinValue(arg.minValue);
363
+ }
364
+ return option;
365
+ });
376
366
  break;
377
367
  }
378
368
  case "number" /* Number */: {
379
- builder.addNumberOption((option) => setupOption(option));
369
+ builder.addNumberOption((data) => {
370
+ const option = setupOption(data);
371
+ if (arg.maxValue) {
372
+ option.setMaxValue(arg.maxValue);
373
+ }
374
+ if (arg.minValue) {
375
+ option.setMinValue(arg.minValue);
376
+ }
377
+ return option;
378
+ });
380
379
  break;
381
380
  }
382
381
  case "user" /* User */:
@@ -564,13 +563,13 @@ var ArgumentResolver = class _ArgumentResolver {
564
563
  return this.options.message.client;
565
564
  }
566
565
  static create(message) {
567
- const client2 = message.client;
568
- const { enableMentionPrefix } = client2.options;
566
+ const client = message.client;
567
+ const { enableMentionPrefix } = client.options;
569
568
  const prefixes = [
570
569
  // Custom prefixes specified in options
571
- ...client2.options.prefixes ?? [],
570
+ ...client.options.prefixes ?? [],
572
571
  // Use bot mention as prefix if enabled
573
- ...enableMentionPrefix ? [client2.user.toString()] : []
572
+ ...enableMentionPrefix ? [client.user.toString()] : []
574
573
  ];
575
574
  const prefix = prefixes.find((p) => message.content.startsWith(p)) ?? null;
576
575
  if (!prefix) {
@@ -813,191 +812,171 @@ var StateBox = class _StateBox {
813
812
  };
814
813
 
815
814
  // src/listener/ListenerEntry.ts
816
- var ListenerHookExecutionState = /* @__PURE__ */ ((ListenerHookExecutionState2) => {
817
- ListenerHookExecutionState2["Main"] = "main";
818
- ListenerHookExecutionState2["Pre"] = "pre";
819
- ListenerHookExecutionState2["Post"] = "post";
820
- ListenerHookExecutionState2["Error"] = "error";
821
- return ListenerHookExecutionState2;
822
- })(ListenerHookExecutionState || {});
823
- var ListenerEntry = class _ListenerEntry {
815
+ var ListenerEntry = class extends BaseEntry {
824
816
  constructor(options) {
817
+ super();
825
818
  this.options = options;
826
819
  }
827
- static hooksKey = Symbol("hooks");
828
- static cache = /* @__PURE__ */ new WeakMap();
829
- main = _ListenerEntry.createMainHookDecorator("main" /* Main */, this);
830
- pre = _ListenerEntry.createMainHookDecorator("pre" /* Pre */, this);
831
- post = _ListenerEntry.createMainHookDecorator("post" /* Post */, this);
832
- error = _ListenerEntry.createErrorHookDecorator("error" /* Error */, this);
833
- static getHooks(constructor, init = false) {
834
- const { cache: cache2 } = this;
835
- let hooks = cache2.get(constructor) ?? Reflect.getMetadata(this.hooksKey, constructor);
836
- if (!hooks) {
837
- hooks = [];
838
- if (init) {
839
- Reflect.defineMetadata(this.hooksKey, hooks, constructor);
840
- this.cache.set(
841
- constructor,
842
- hooks
843
- );
844
- }
845
- }
846
- return init ? hooks : [...hooks];
847
- }
848
- static createMainHookDecorator(state, entry) {
849
- return (target, _key, descriptor) => {
850
- this.addHook(target, state, descriptor.value, entry);
851
- };
852
- }
853
- static createErrorHookDecorator(state, entry) {
854
- return (target, _key, descriptor) => {
855
- this.addHook(target, state, descriptor.value, entry);
856
- };
857
- }
858
- static addHook(target, state, method, entry) {
859
- const { constructor } = target;
860
- const hooks = this.getHooks(constructor, true);
861
- if (typeof method !== "function") {
862
- throw new Error("CommandEntry decorator must be used with a class method.");
863
- }
864
- if (hooks.some((hook2) => hook2.state === state && hook2.entry === entry)) {
865
- throw new Error(
866
- `Hook "${state}" is already defined for entry "${String(entry.options.name)}".`
867
- );
868
- }
869
- const hook = {
870
- state,
871
- entry,
872
- method
873
- };
874
- hooks.push(hook);
875
- }
876
820
  };
877
821
 
878
822
  // src/listener/Listener.ts
823
+ var ListenerAPI;
824
+ ((ListenerAPI2) => {
825
+ ListenerAPI2.ENTRY_KEY = Symbol("entry");
826
+ function use(entry) {
827
+ return (target) => {
828
+ Reflect.defineMetadata(ListenerAPI2.ENTRY_KEY, entry, target);
829
+ };
830
+ }
831
+ ListenerAPI2.use = use;
832
+ function getEntry(target) {
833
+ return Reflect.getMetadata(ListenerAPI2.ENTRY_KEY, target);
834
+ }
835
+ ListenerAPI2.getEntry = getEntry;
836
+ })(ListenerAPI || (ListenerAPI = {}));
879
837
  function ListenerFactory(options) {
880
- const normalizedOptions = typeof options === "object" ? { once: false, ...options } : { name: options, once: false };
881
- return new ListenerEntry(normalizedOptions);
838
+ const fullOptions = typeof options !== "object" ? { name: options, once: false } : { once: false, ...options };
839
+ return new ListenerEntry(fullOptions);
882
840
  }
883
- var LISTENER_ENTRY_KEY = Symbol("entry");
884
- function use2(listener) {
885
- return (target) => {
886
- Reflect.defineMetadata(LISTENER_ENTRY_KEY, listener, target);
887
- };
888
- }
889
- function getEntry(constructor) {
890
- return Reflect.getMetadata(LISTENER_ENTRY_KEY, constructor);
891
- }
892
- var Listener = Object.assign(ListenerFactory, {
893
- use: use2,
894
- getEntry
895
- });
841
+ var Listener = Object.assign(ListenerFactory, ListenerAPI);
896
842
 
897
843
  // src/listener/ListenerRegistry.ts
898
- var client;
899
- var constructors = /* @__PURE__ */ new Set();
900
- var instances = /* @__PURE__ */ new WeakMap();
901
- var executors = /* @__PURE__ */ new WeakMap();
902
- function add(constructor) {
903
- const entry = Listener.getEntry(constructor);
904
- if (!entry) {
905
- throw new Error(`No entry found for "${constructor.name}"`);
906
- }
907
- const { options } = entry;
908
- if (!options.emitter) {
909
- if (!client) {
910
- throw new Error("Client is not ready.");
911
- }
912
- options.emitter = client;
913
- }
914
- const instance = new constructor();
915
- constructors.add(constructor);
916
- instances.set(constructor, instance);
917
- const executor = createExecutor(constructor, instance);
918
- executors.set(instance, executor);
919
- options.emitter[options.once ? "once" : "on"](options.name, (...args) => {
920
- void executor(...args);
921
- });
922
- }
923
- function remove(constructor) {
924
- const entry = Listener.getEntry(constructor);
925
- if (!entry) {
926
- return;
927
- }
928
- constructors.delete(constructor);
929
- const instance = instances.get(constructor);
930
- if (!instance) {
931
- return;
932
- }
933
- instances.delete(constructor);
934
- const executor = executors.get(instance);
935
- if (!executor) {
936
- return;
937
- }
938
- const { name, emitter } = entry.options;
939
- emitter?.removeListener(name, executor);
940
- executors.delete(instance);
941
- }
942
- function removeAll() {
943
- for (const constructor of constructors) {
944
- remove(constructor);
945
- }
946
- }
947
- function setClient(newClient) {
948
- client = newClient;
949
- }
950
- function createExecutor(constructor, instance) {
951
- const entry = Listener.getEntry(constructor);
952
- if (!entry) {
953
- throw new Error("Missing listener entry");
954
- }
955
- const hooks = ListenerEntry.getHooks(constructor).filter((hook) => hook.entry === entry);
956
- const hookGroup = makeHookGroup(hooks);
957
- return async function(...args) {
958
- if (!hookGroup.main) {
959
- return;
844
+ import glob2 from "tiny-glob";
845
+ import { pathToFileURL as pathToFileURL2 } from "url";
846
+ var ListenerRegistry = class {
847
+ static client;
848
+ static constructors = /* @__PURE__ */ new Set();
849
+ static instances = /* @__PURE__ */ new WeakMap();
850
+ static executors = /* @__PURE__ */ new WeakMap();
851
+ /**
852
+ * Add and register a listener to the registry.
853
+ * If `options.emitter` is not provided, the registry will use the base `client` by default.
854
+ * @param constructor The listener class you want to add.
855
+ */
856
+ static add(constructor) {
857
+ const entry = Listener.getEntry(constructor);
858
+ if (!entry) {
859
+ throw new Error(`No entry found for "${constructor.name}"`);
960
860
  }
961
- try {
962
- if (hookGroup.pre) {
963
- const preMethod = hookGroup.pre.method;
964
- await preMethod.call(instance, ...args);
861
+ const { options } = entry;
862
+ if (!options.emitter) {
863
+ if (!this.client) {
864
+ throw new Error("Client is not ready.");
965
865
  }
966
- await hookGroup.main.method.call(instance, ...args);
967
- if (hookGroup.post) {
968
- const postMethod = hookGroup.post.method;
969
- await postMethod.call(instance, ...args);
866
+ options.emitter = this.client;
867
+ }
868
+ const instance = new constructor();
869
+ const executor = this.createExecutor(constructor, instance);
870
+ this.constructors.add(constructor);
871
+ this.instances.set(constructor, instance);
872
+ this.executors.set(instance, executor);
873
+ options.emitter[options.once ? "once" : "on"](options.name, (...args) => {
874
+ void executor(...args);
875
+ });
876
+ }
877
+ /**
878
+ * Remove and unregister a listener from the registry.
879
+ * @param constructor The listener class you want to remove.
880
+ * @returns `boolean`, returns `true` if the listener is removed successfully.
881
+ */
882
+ static remove(constructor) {
883
+ const entry = Listener.getEntry(constructor);
884
+ if (!entry) {
885
+ return false;
886
+ }
887
+ this.constructors.delete(constructor);
888
+ const instance = this.instances.get(constructor);
889
+ if (!instance) {
890
+ return false;
891
+ }
892
+ this.instances.delete(constructor);
893
+ const executor = this.executors.get(instance);
894
+ if (!executor) {
895
+ return false;
896
+ }
897
+ const { name, emitter } = entry.options;
898
+ emitter?.removeListener(name, executor);
899
+ this.executors.delete(instance);
900
+ return true;
901
+ }
902
+ /**
903
+ * Remove and unregister all listeners from the registry.
904
+ * @returns Amount of removed listeners.
905
+ */
906
+ static removeAll() {
907
+ let removedAmount = 0;
908
+ for (const constructor of this.constructors) {
909
+ if (this.remove(constructor)) {
910
+ removedAmount++;
970
911
  }
971
- } catch (error) {
972
- if (hookGroup.error) {
973
- const errorMethod = hookGroup.error.method;
974
- await errorMethod.call(instance, error, ...args);
975
- } else {
976
- throw error;
912
+ }
913
+ return removedAmount;
914
+ }
915
+ /**
916
+ * Set base client for the registry to fallback as default emitter. This should be used only by BakitClient and stay untouched.
917
+ * @param newClient base client to set for the registry.
918
+ */
919
+ static setClient(newClient) {
920
+ this.client = newClient;
921
+ }
922
+ static createExecutor(constructor, instance) {
923
+ const entry = Listener.getEntry(constructor);
924
+ if (!entry) {
925
+ throw new Error("Missing listener entry");
926
+ }
927
+ const { hooks } = entry;
928
+ return async function(...args) {
929
+ const mainHook = hooks["MAIN" /* Main */];
930
+ const preHook = hooks["PRE" /* Pre */];
931
+ const postHook = hooks["POST" /* Post */];
932
+ const errorHook = hooks["ERROR" /* Error */];
933
+ if (!mainHook) {
934
+ return;
935
+ }
936
+ try {
937
+ if (preHook) {
938
+ await preHook.method.call(instance, ...args);
939
+ }
940
+ await mainHook.method.call(instance, ...args);
941
+ if (postHook) {
942
+ await postHook.method.call(instance, ...args);
943
+ }
944
+ } catch (error) {
945
+ if (errorHook) {
946
+ await errorHook.method.call(
947
+ instance,
948
+ error,
949
+ ...args
950
+ );
951
+ } else {
952
+ throw error;
953
+ }
977
954
  }
955
+ };
956
+ }
957
+ /**
958
+ * Load and add all listeners which matched provided glob pattern to the registry.
959
+ * @param pattern glob pattern to load.
960
+ * @param parallel load all matched results in parallel, enabled by default.
961
+ * @returns All loaded listener constructors.
962
+ */
963
+ static async load(pattern, parallel = true) {
964
+ const files = await glob2(pattern);
965
+ const loaders = files.map(async (file) => {
966
+ const fileURL = pathToFileURL2(file).toString();
967
+ const { default: constructor } = await import(fileURL);
968
+ this.add(constructor);
969
+ return constructor;
970
+ });
971
+ if (parallel) {
972
+ return Promise.all(loaders);
978
973
  }
979
- };
980
- }
981
- function makeHookGroup(hooks) {
982
- const hooksByType = {
983
- ["pre" /* Pre */]: void 0,
984
- ["main" /* Main */]: void 0,
985
- ["post" /* Post */]: void 0,
986
- ["error" /* Error */]: void 0
987
- };
988
- for (const hook of hooks) {
989
- hooksByType[hook.state] = hook;
974
+ const result = [];
975
+ for (const loader of loaders) {
976
+ result.push(await loader);
977
+ }
978
+ return result;
990
979
  }
991
- return hooksByType;
992
- }
993
- var ListenerRegistry = {
994
- constructors,
995
- instances,
996
- executors,
997
- add,
998
- setClient,
999
- remove,
1000
- removeAll
1001
980
  };
1002
981
 
1003
982
  // src/BakitClient.ts
@@ -1007,10 +986,10 @@ var BakitClient = class _BakitClient extends Client {
1007
986
  options.getSyntaxErrorMessage = _BakitClient.getSyntaxErrorMessage;
1008
987
  }
1009
988
  super(options);
1010
- ListenerRegistry.setClient(this);
989
+ ListenerRegistry["setClient"](this);
1011
990
  this.once(
1012
991
  Events.ClientReady,
1013
- (client2) => void this.registerApplicationCommands(client2)
992
+ (client) => void this.registerApplicationCommands(client)
1014
993
  );
1015
994
  this.on(Events.InteractionCreate, (interaction) => void this.handleInteraction(interaction));
1016
995
  this.on(Events.MessageCreate, (message) => void this.handleMessage(message));
@@ -1030,14 +1009,15 @@ var BakitClient = class _BakitClient extends Client {
1030
1009
  content
1031
1010
  };
1032
1011
  };
1033
- async registerApplicationCommands(client2) {
1012
+ async registerApplicationCommands(client) {
1034
1013
  const commands = CommandRegistry.constructors.map((c) => CommandRegistry.buildSlashCommand(c));
1035
- await client2.application.commands.set(commands);
1014
+ await client.application.commands.set(commands);
1036
1015
  }
1037
1016
  async handleMessage(message) {
1038
1017
  if (message.author.bot) {
1039
1018
  return;
1040
1019
  }
1020
+ const context = new MessageContext(message);
1041
1021
  const resolver = ArgumentResolver.create(message);
1042
1022
  if (!resolver) {
1043
1023
  return;
@@ -1047,9 +1027,7 @@ var BakitClient = class _BakitClient extends Client {
1047
1027
  if (!command) {
1048
1028
  return;
1049
1029
  }
1050
- const hooks = BaseCommandEntry.getHooks(command.constructor);
1051
- const context = new MessageContext(message);
1052
- await StateBox.run(() => this.handleMessageHooks(context, hooks, command, resolver));
1030
+ await StateBox.run(() => this.handleMessageHooks(context, command, resolver));
1053
1031
  }
1054
1032
  async handleInteraction(interaction) {
1055
1033
  if (!interaction.isChatInputCommand()) {
@@ -1060,54 +1038,57 @@ var BakitClient = class _BakitClient extends Client {
1060
1038
  if (!command) {
1061
1039
  return;
1062
1040
  }
1063
- const hooks = BaseCommandEntry.getHooks(command.constructor);
1064
1041
  const context = new ChatInputContext(interaction);
1065
- await StateBox.run(() => this.handleChatInputHooks(context, hooks, command));
1042
+ await StateBox.run(() => this.handleChatInputHooks(context, command));
1066
1043
  }
1067
- async handleChatInputHooks(context, hooks, instance) {
1068
- const targetHooks = this.getChatInputTargetHooks(context.source, hooks);
1044
+ async handleChatInputHooks(context, instance) {
1045
+ const targetHooks = this.getChatInputTargetHooks(context.source, instance);
1069
1046
  let inheritedArgs = [];
1070
- for (const record of [targetHooks.root, targetHooks.group, targetHooks.subcommand]) {
1071
- const newArgs = await this.runChatInputHooks(context, instance, record, inheritedArgs);
1047
+ for (const hooks of [targetHooks.root, targetHooks.group, targetHooks.subcommand]) {
1048
+ if (!hooks) {
1049
+ continue;
1050
+ }
1051
+ const newArgs = await this.runChatInputHooks(context, instance, hooks, inheritedArgs);
1072
1052
  if (newArgs) {
1073
1053
  inheritedArgs = newArgs;
1074
1054
  }
1075
1055
  }
1076
1056
  }
1077
- async handleMessageHooks(context, hooks, instance, resolver) {
1057
+ async handleMessageHooks(context, instance, resolver) {
1078
1058
  if (!resolver) {
1079
1059
  return;
1080
1060
  }
1081
- const rootEntry = Command.getRoot(instance.constructor);
1082
- if (!rootEntry) return;
1083
- const rootRecord = this.createHookRecord(hooks.filter((hook) => hook.entry === rootEntry));
1084
- resolver = await this.runMessageHooks(context, instance, rootRecord, resolver);
1061
+ const root = Command.getRoot(instance.constructor);
1062
+ if (!root) {
1063
+ return;
1064
+ }
1065
+ resolver = await this.runMessageHooks(context, instance, root.hooks, resolver);
1085
1066
  if (!resolver) {
1086
1067
  return;
1087
1068
  }
1088
- const usedValues = resolver.parsedValues.length;
1089
- const nextTrigger = resolver.values[usedValues + 1];
1090
- const nextHook = hooks.find((hook) => hook.entry.options.name === nextTrigger);
1091
- const nextRecord = this.createHookRecord(nextHook ? [nextHook] : []);
1092
- resolver = await this.runMessageHooks(context, instance, nextRecord, resolver);
1069
+ await this.handleChildMessageHooks(context, root, instance, resolver);
1070
+ }
1071
+ async handleChildMessageHooks(context, parent, instance, resolver, skip = 1) {
1093
1072
  if (!resolver) {
1094
1073
  return;
1095
1074
  }
1096
- if (nextRecord.main?.entry instanceof CommandGroupEntry) {
1097
- const groupEntry = nextRecord.main.entry;
1098
- const subTrigger = resolver.values[usedValues + 2];
1099
- const subHook = hooks.find(
1100
- (h) => h.entry instanceof SubcommandEntry && h.entry.options.name === subTrigger && h.entry.parent === groupEntry
1101
- );
1102
- const subRecord = this.createHookRecord(subHook ? [subHook] : []);
1103
- resolver = await this.runMessageHooks(context, instance, subRecord, resolver);
1075
+ const usedValues = resolver.parsedValues.length;
1076
+ const nextTrigger = resolver.values[usedValues + skip];
1077
+ const child = parent.children.get(nextTrigger);
1078
+ if (!child) {
1079
+ return;
1080
+ }
1081
+ resolver = await this.runMessageHooks(context, instance, child.hooks, resolver);
1082
+ if (child instanceof CommandGroupEntry) {
1083
+ await this.handleChildMessageHooks(context, child, instance, resolver, skip + 1);
1104
1084
  }
1105
1085
  }
1106
- async runMessageHooks(context, instance, record, resolver) {
1107
- if (!record.main) {
1086
+ async runMessageHooks(context, instance, hooks, resolver) {
1087
+ const mainHook = hooks["MAIN" /* Main */];
1088
+ if (!mainHook) {
1108
1089
  return resolver;
1109
1090
  }
1110
- const args = Arg.getMethodArguments(record.main.method);
1091
+ const args = Arg.getMethodArguments(mainHook.method);
1111
1092
  try {
1112
1093
  resolver = await resolver.resolve(args);
1113
1094
  } catch (error) {
@@ -1126,75 +1107,78 @@ var BakitClient = class _BakitClient extends Client {
1126
1107
  }
1127
1108
  throw error;
1128
1109
  }
1129
- try {
1130
- await record.pre?.method.call(instance, context, ...resolver.parsedValues);
1131
- await record.main.method.call(instance, context, ...resolver.parsedValues);
1132
- await record.post?.method.call(instance, context, ...resolver.parsedValues);
1133
- } catch (error) {
1134
- if (record.error) {
1135
- await record.error.method.call(instance, context, error, ...resolver.parsedValues);
1136
- } else {
1137
- throw error;
1138
- }
1139
- }
1110
+ await this.runHooks(context, instance, hooks, resolver.parsedValues);
1140
1111
  return resolver;
1141
1112
  }
1142
- async runChatInputHooks(context, instance, record, inheritedArgs) {
1143
- if (!record.main) {
1113
+ async runChatInputHooks(context, instance, hooks, inheritedArgs) {
1114
+ const mainHook = hooks["MAIN" /* Main */];
1115
+ if (!mainHook) {
1144
1116
  return;
1145
1117
  }
1146
- const newArgs = Arg.getMethodArguments(record.main.method).map(
1118
+ const newArgs = Arg.getMethodArguments(mainHook.method).map(
1147
1119
  (arg) => ArgumentResolver.resolveChatInput(context.source, arg)
1148
1120
  );
1149
1121
  const argValues = [...inheritedArgs, ...newArgs];
1122
+ await this.runHooks(context, instance, hooks, argValues);
1123
+ return argValues;
1124
+ }
1125
+ async runHooks(context, instance, hooks, args) {
1126
+ const mainHook = hooks["MAIN" /* Main */];
1127
+ const preHook = hooks["PRE" /* Pre */];
1128
+ const postHook = hooks["POST" /* Post */];
1129
+ const errorHook = hooks["ERROR" /* Error */];
1130
+ if (!mainHook) {
1131
+ return;
1132
+ }
1133
+ const execute = async (hook, error) => {
1134
+ if (!hook) {
1135
+ return;
1136
+ }
1137
+ if (hook.state === "ERROR" /* Error */) {
1138
+ await hook.method.call(instance, error, context, ...args);
1139
+ } else {
1140
+ await hook.method.call(instance, context, ...args);
1141
+ }
1142
+ };
1150
1143
  try {
1151
- await record.pre?.method.call(instance, context, ...argValues);
1152
- await record.main.method.call(instance, context, ...argValues);
1153
- await record.post?.method.call(instance, context, ...argValues);
1144
+ await execute(preHook);
1145
+ await execute(mainHook);
1146
+ await execute(postHook);
1154
1147
  } catch (error) {
1155
- if (record.error) {
1156
- await record.error.method.call(instance, context, error, ...argValues);
1148
+ if (errorHook) {
1149
+ await execute(errorHook, error);
1157
1150
  } else {
1158
1151
  throw error;
1159
1152
  }
1160
1153
  }
1161
- return argValues;
1162
1154
  }
1163
- getChatInputTargetHooks(interaction, hooks) {
1164
- const subcommand = interaction.options.getSubcommand(false);
1165
- const subcommandGroup = interaction.options.getSubcommandGroup(false);
1166
- const root = this.createHookRecord(
1167
- hooks.filter((hook) => hook.entry instanceof RootCommandEntry)
1168
- );
1169
- const group = this.createHookRecord(
1170
- hooks.filter(({ entry }) => {
1171
- return entry instanceof CommandGroupEntry && entry.options.name === subcommandGroup;
1172
- })
1173
- );
1174
- const sub = this.createHookRecord(
1175
- hooks.filter(({ entry }) => {
1176
- if (!(entry instanceof SubcommandEntry) || !(entry.options.name === subcommand)) {
1177
- return false;
1178
- }
1179
- if (subcommandGroup) {
1180
- const { parent } = entry;
1181
- if (!(parent instanceof CommandGroupEntry) || parent.options.name !== subcommandGroup) {
1182
- return false;
1183
- }
1184
- }
1185
- return true;
1186
- })
1187
- );
1188
- return { root, group, subcommand: sub };
1189
- }
1190
- createHookRecord(hooks) {
1191
- return Object.values(CommandHookExecutionState).reduce(
1192
- (acc, state) => {
1193
- acc[state] = hooks.find((h) => h.state === state);
1194
- return acc;
1195
- },
1196
- {}
1197
- );
1155
+ getChatInputTargetHooks(interaction, instance) {
1156
+ const subcommandName = interaction.options.getSubcommand(false);
1157
+ const groupName = interaction.options.getSubcommandGroup(false);
1158
+ const root = Command.getRoot(instance.constructor);
1159
+ if (!root) {
1160
+ throw new Error("No root found.");
1161
+ }
1162
+ let group;
1163
+ if (groupName) {
1164
+ const child = root.children.get(groupName);
1165
+ if (child instanceof CommandGroupEntry) {
1166
+ group = child;
1167
+ }
1168
+ }
1169
+ let subcommand;
1170
+ if (subcommandName) {
1171
+ const parent = group || root;
1172
+ const child = parent.children.get(subcommandName);
1173
+ if (child instanceof SubcommandEntry) {
1174
+ subcommand = child;
1175
+ }
1176
+ }
1177
+ return {
1178
+ root: root.hooks,
1179
+ group: group?.hooks,
1180
+ subcommand: subcommand?.hooks
1181
+ };
1198
1182
  }
1199
1183
  };
1200
1184
  export {
@@ -1206,18 +1190,16 @@ export {
1206
1190
  BaseContext,
1207
1191
  ChatInputContext,
1208
1192
  Command,
1193
+ CommandAPI,
1209
1194
  CommandFactory,
1210
1195
  CommandGroupEntry,
1211
- CommandHookExecutionState,
1212
1196
  CommandRegistry,
1213
1197
  CommandSyntaxError,
1214
1198
  CommandSyntaxErrorType,
1215
- HOOKS_KEY,
1216
- LISTENER_ENTRY_KEY,
1217
1199
  Listener,
1200
+ ListenerAPI,
1218
1201
  ListenerEntry,
1219
1202
  ListenerFactory,
1220
- ListenerHookExecutionState,
1221
1203
  ListenerRegistry,
1222
1204
  MessageContext,
1223
1205
  RootCommandEntry,