bakit 1.0.0-beta.4 → 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,137 +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
- let hooks = this.cache.get(constructor) ?? Reflect.getMetadata(this.hooksKey, constructor);
835
- if (!hooks) {
836
- hooks = [];
837
- if (init) {
838
- Reflect.defineMetadata(this.hooksKey, hooks, constructor);
839
- this.cache.set(constructor, hooks);
840
- }
841
- }
842
- return init ? hooks : Object.freeze([...hooks]);
843
- }
844
- static createMainHookDecorator(state, entry) {
845
- return (target, _key, descriptor) => {
846
- this.addHook(target, state, descriptor.value, entry);
847
- };
848
- }
849
- static createErrorHookDecorator(state, entry) {
850
- return (target, _key, descriptor) => {
851
- this.addHook(target, state, descriptor.value, entry);
852
- };
853
- }
854
- static addHook(target, state, method, entry) {
855
- const { constructor } = target;
856
- const hooks = this.getHooks(constructor, true);
857
- if (typeof method !== "function") {
858
- throw new Error("CommandEntry decorator must be used with a class method.");
859
- }
860
- if (hooks.some((hook2) => hook2.state === state && hook2.entry === entry)) {
861
- throw new Error(
862
- `Hook "${state}" is already defined for entry "${String(entry.options.name)}".`
863
- );
864
- }
865
- const hook = {
866
- state,
867
- entry,
868
- method
869
- };
870
- hooks.push(hook);
871
- }
872
820
  };
873
821
 
874
822
  // src/listener/Listener.ts
875
- function ListenerFactory(options) {
876
- if (typeof options !== "object") {
877
- options = {
878
- name: options,
879
- once: false
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);
880
829
  };
881
830
  }
882
- options.once = Boolean(options.once);
883
- return new ListenerEntry(options);
884
- }
885
- var ENTRY_KEY = Symbol("entry");
886
- function use2(listener) {
887
- return (target) => {
888
- Reflect.defineMetadata(ENTRY_KEY, listener, target);
889
- };
890
- }
891
- function getEntry(constructor) {
892
- return Reflect.getMetadata(ENTRY_KEY, constructor);
831
+ ListenerAPI2.use = use;
832
+ function getEntry(target) {
833
+ return Reflect.getMetadata(ListenerAPI2.ENTRY_KEY, target);
834
+ }
835
+ ListenerAPI2.getEntry = getEntry;
836
+ })(ListenerAPI || (ListenerAPI = {}));
837
+ function ListenerFactory(options) {
838
+ const fullOptions = typeof options !== "object" ? { name: options, once: false } : { once: false, ...options };
839
+ return new ListenerEntry(fullOptions);
893
840
  }
894
- var Listener = Object.assign(ListenerFactory, {
895
- use: use2,
896
- getEntry
897
- });
841
+ var Listener = Object.assign(ListenerFactory, ListenerAPI);
898
842
 
899
843
  // src/listener/ListenerRegistry.ts
900
- var client;
901
- var constructors = /* @__PURE__ */ new Set();
902
- var instances = /* @__PURE__ */ new WeakMap();
903
- function add(constructor) {
904
- const entry = Listener.getEntry(constructor);
905
- if (!entry) {
906
- throw new Error(`No entry found for "${constructor.name}"`);
907
- }
908
- const { options } = entry;
909
- if (!options.emitter) {
910
- if (!client) {
911
- throw new Error("Client is not ready.");
912
- }
913
- options.emitter = client;
914
- }
915
- constructors.add(constructor);
916
- instances.set(constructor, new constructor());
917
- }
918
- function remove(constructor) {
919
- const entry = Listener.getEntry(constructor);
920
- if (!entry) {
921
- return;
922
- }
923
- constructors.delete(constructor);
924
- instances.delete(constructor);
925
- const hook = ListenerEntry.getHooks(constructor).find((hook2) => hook2.entry === entry);
926
- if (!hook) {
927
- return;
928
- }
929
- const { name, emitter } = entry.options;
930
- emitter?.removeListener(name, hook.method);
931
- }
932
- function removeAll() {
933
- for (const constructor of constructors) {
934
- remove(constructor);
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}"`);
860
+ }
861
+ const { options } = entry;
862
+ if (!options.emitter) {
863
+ if (!this.client) {
864
+ throw new Error("Client is not ready.");
865
+ }
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++;
911
+ }
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
+ }
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);
973
+ }
974
+ const result = [];
975
+ for (const loader of loaders) {
976
+ result.push(await loader);
977
+ }
978
+ return result;
935
979
  }
936
- }
937
- function setClient(newClient) {
938
- client = newClient;
939
- }
940
- var ListenerRegistry = {
941
- constructors,
942
- instances,
943
- add,
944
- setClient,
945
- remove,
946
- removeAll
947
980
  };
948
981
 
949
982
  // src/BakitClient.ts
@@ -953,10 +986,10 @@ var BakitClient = class _BakitClient extends Client {
953
986
  options.getSyntaxErrorMessage = _BakitClient.getSyntaxErrorMessage;
954
987
  }
955
988
  super(options);
956
- ListenerRegistry.setClient(this);
989
+ ListenerRegistry["setClient"](this);
957
990
  this.once(
958
991
  Events.ClientReady,
959
- (client2) => void this.registerApplicationCommands(client2)
992
+ (client) => void this.registerApplicationCommands(client)
960
993
  );
961
994
  this.on(Events.InteractionCreate, (interaction) => void this.handleInteraction(interaction));
962
995
  this.on(Events.MessageCreate, (message) => void this.handleMessage(message));
@@ -976,14 +1009,15 @@ var BakitClient = class _BakitClient extends Client {
976
1009
  content
977
1010
  };
978
1011
  };
979
- async registerApplicationCommands(client2) {
1012
+ async registerApplicationCommands(client) {
980
1013
  const commands = CommandRegistry.constructors.map((c) => CommandRegistry.buildSlashCommand(c));
981
- await client2.application.commands.set(commands);
1014
+ await client.application.commands.set(commands);
982
1015
  }
983
1016
  async handleMessage(message) {
984
1017
  if (message.author.bot) {
985
1018
  return;
986
1019
  }
1020
+ const context = new MessageContext(message);
987
1021
  const resolver = ArgumentResolver.create(message);
988
1022
  if (!resolver) {
989
1023
  return;
@@ -993,9 +1027,7 @@ var BakitClient = class _BakitClient extends Client {
993
1027
  if (!command) {
994
1028
  return;
995
1029
  }
996
- const hooks = BaseCommandEntry.getHooks(command.constructor);
997
- const context = new MessageContext(message);
998
- await StateBox.run(() => this.handleMessageHooks(context, hooks, command, resolver));
1030
+ await StateBox.run(() => this.handleMessageHooks(context, command, resolver));
999
1031
  }
1000
1032
  async handleInteraction(interaction) {
1001
1033
  if (!interaction.isChatInputCommand()) {
@@ -1006,54 +1038,57 @@ var BakitClient = class _BakitClient extends Client {
1006
1038
  if (!command) {
1007
1039
  return;
1008
1040
  }
1009
- const hooks = BaseCommandEntry.getHooks(command.constructor);
1010
1041
  const context = new ChatInputContext(interaction);
1011
- await StateBox.run(() => this.handleChatInputHooks(context, hooks, command));
1042
+ await StateBox.run(() => this.handleChatInputHooks(context, command));
1012
1043
  }
1013
- async handleChatInputHooks(context, hooks, instance) {
1014
- const targetHooks = this.getChatInputTargetHooks(context.source, hooks);
1044
+ async handleChatInputHooks(context, instance) {
1045
+ const targetHooks = this.getChatInputTargetHooks(context.source, instance);
1015
1046
  let inheritedArgs = [];
1016
- for (const record of [targetHooks.root, targetHooks.group, targetHooks.subcommand]) {
1017
- 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);
1018
1052
  if (newArgs) {
1019
1053
  inheritedArgs = newArgs;
1020
1054
  }
1021
1055
  }
1022
1056
  }
1023
- async handleMessageHooks(context, hooks, instance, resolver) {
1057
+ async handleMessageHooks(context, instance, resolver) {
1024
1058
  if (!resolver) {
1025
1059
  return;
1026
1060
  }
1027
- const rootEntry = Command.getRoot(instance.constructor);
1028
- if (!rootEntry) return;
1029
- const rootRecord = this.createHookRecord(hooks.filter((hook) => hook.entry === rootEntry));
1030
- 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);
1031
1066
  if (!resolver) {
1032
1067
  return;
1033
1068
  }
1034
- const usedValues = resolver.parsedValues.length;
1035
- const nextTrigger = resolver.values[usedValues + 1];
1036
- const nextHook = hooks.find((hook) => hook.entry.options.name === nextTrigger);
1037
- const nextRecord = this.createHookRecord(nextHook ? [nextHook] : []);
1038
- 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) {
1039
1072
  if (!resolver) {
1040
1073
  return;
1041
1074
  }
1042
- if (nextRecord.main?.entry instanceof CommandGroupEntry) {
1043
- const groupEntry = nextRecord.main.entry;
1044
- const subTrigger = resolver.values[usedValues + 2];
1045
- const subHook = hooks.find(
1046
- (h) => h.entry instanceof SubcommandEntry && h.entry.options.name === subTrigger && h.entry.parent === groupEntry
1047
- );
1048
- const subRecord = this.createHookRecord(subHook ? [subHook] : []);
1049
- 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);
1050
1084
  }
1051
1085
  }
1052
- async runMessageHooks(context, instance, record, resolver) {
1053
- if (!record.main) {
1086
+ async runMessageHooks(context, instance, hooks, resolver) {
1087
+ const mainHook = hooks["MAIN" /* Main */];
1088
+ if (!mainHook) {
1054
1089
  return resolver;
1055
1090
  }
1056
- const args = Arg.getMethodArguments(record.main.method);
1091
+ const args = Arg.getMethodArguments(mainHook.method);
1057
1092
  try {
1058
1093
  resolver = await resolver.resolve(args);
1059
1094
  } catch (error) {
@@ -1072,75 +1107,78 @@ var BakitClient = class _BakitClient extends Client {
1072
1107
  }
1073
1108
  throw error;
1074
1109
  }
1075
- try {
1076
- await record.pre?.method.call(instance, context, ...resolver.parsedValues);
1077
- await record.main.method.call(instance, context, ...resolver.parsedValues);
1078
- await record.post?.method.call(instance, context, ...resolver.parsedValues);
1079
- } catch (error) {
1080
- if (record.error) {
1081
- await record.error.method.call(instance, context, error, ...resolver.parsedValues);
1082
- } else {
1083
- throw error;
1084
- }
1085
- }
1110
+ await this.runHooks(context, instance, hooks, resolver.parsedValues);
1086
1111
  return resolver;
1087
1112
  }
1088
- async runChatInputHooks(context, instance, record, inheritedArgs) {
1089
- if (!record.main) {
1113
+ async runChatInputHooks(context, instance, hooks, inheritedArgs) {
1114
+ const mainHook = hooks["MAIN" /* Main */];
1115
+ if (!mainHook) {
1090
1116
  return;
1091
1117
  }
1092
- const newArgs = Arg.getMethodArguments(record.main.method).map(
1118
+ const newArgs = Arg.getMethodArguments(mainHook.method).map(
1093
1119
  (arg) => ArgumentResolver.resolveChatInput(context.source, arg)
1094
1120
  );
1095
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
+ };
1096
1143
  try {
1097
- await record.pre?.method.call(instance, context, ...argValues);
1098
- await record.main.method.call(instance, context, ...argValues);
1099
- await record.post?.method.call(instance, context, ...argValues);
1144
+ await execute(preHook);
1145
+ await execute(mainHook);
1146
+ await execute(postHook);
1100
1147
  } catch (error) {
1101
- if (record.error) {
1102
- await record.error.method.call(instance, context, error, ...argValues);
1148
+ if (errorHook) {
1149
+ await execute(errorHook, error);
1103
1150
  } else {
1104
1151
  throw error;
1105
1152
  }
1106
1153
  }
1107
- return argValues;
1108
1154
  }
1109
- getChatInputTargetHooks(interaction, hooks) {
1110
- const subcommand = interaction.options.getSubcommand(false);
1111
- const subcommandGroup = interaction.options.getSubcommandGroup(false);
1112
- const root = this.createHookRecord(
1113
- hooks.filter((hook) => hook.entry instanceof RootCommandEntry)
1114
- );
1115
- const group = this.createHookRecord(
1116
- hooks.filter(({ entry }) => {
1117
- return entry instanceof CommandGroupEntry && entry.options.name === subcommandGroup;
1118
- })
1119
- );
1120
- const sub = this.createHookRecord(
1121
- hooks.filter(({ entry }) => {
1122
- if (!(entry instanceof SubcommandEntry) || !(entry.options.name === subcommand)) {
1123
- return false;
1124
- }
1125
- if (subcommandGroup) {
1126
- const { parent } = entry;
1127
- if (!(parent instanceof CommandGroupEntry) || parent.options.name !== subcommandGroup) {
1128
- return false;
1129
- }
1130
- }
1131
- return true;
1132
- })
1133
- );
1134
- return { root, group, subcommand: sub };
1135
- }
1136
- createHookRecord(hooks) {
1137
- return Object.values(CommandHookExecutionState).reduce(
1138
- (acc, state) => {
1139
- acc[state] = hooks.find((h) => h.state === state);
1140
- return acc;
1141
- },
1142
- {}
1143
- );
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
+ };
1144
1182
  }
1145
1183
  };
1146
1184
  export {
@@ -1152,17 +1190,16 @@ export {
1152
1190
  BaseContext,
1153
1191
  ChatInputContext,
1154
1192
  Command,
1193
+ CommandAPI,
1155
1194
  CommandFactory,
1156
1195
  CommandGroupEntry,
1157
- CommandHookExecutionState,
1158
1196
  CommandRegistry,
1159
1197
  CommandSyntaxError,
1160
1198
  CommandSyntaxErrorType,
1161
- HOOKS_KEY,
1162
1199
  Listener,
1200
+ ListenerAPI,
1163
1201
  ListenerEntry,
1164
1202
  ListenerFactory,
1165
- ListenerHookExecutionState,
1166
1203
  ListenerRegistry,
1167
1204
  MessageContext,
1168
1205
  RootCommandEntry,