@pikokr/command.ts 4.0.6 → 5.0.0-dev.572678b

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 (95) hide show
  1. package/.github/workflows/codeql-analysis.yml +70 -0
  2. package/.github/workflows/docs.yml +1 -1
  3. package/.github/workflows/publish.stable.yml +1 -1
  4. package/.github/workflows/publish.yml +1 -1
  5. package/.vscode/settings.json +10 -0
  6. package/.vscode/templates/ts.lict +5 -0
  7. package/README.md +2 -0
  8. package/dist/index.d.ts +134 -296
  9. package/dist/index.js +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/docs/index.yml +1 -1
  12. package/package.json +21 -14
  13. package/publish-version.js +20 -0
  14. package/renovate.json +5 -0
  15. package/scripts/docs.ts +8 -4
  16. package/src/applicationCommand/ApplicationCommand.ts +17 -0
  17. package/src/applicationCommand/ApplicationCommandExtension.ts +169 -0
  18. package/src/applicationCommand/ApplicationCommandOption.ts +16 -0
  19. package/src/applicationCommand/index.ts +10 -6
  20. package/src/core/components/BaseComponent.ts +56 -0
  21. package/src/core/components/ComponentArgument.ts +15 -0
  22. package/src/core/components/ComponentArgumentDecorator.ts +25 -0
  23. package/src/core/components/decoratorCreator.ts +81 -0
  24. package/src/core/components/index.ts +13 -0
  25. package/src/core/converter/index.ts +16 -0
  26. package/src/core/extensions/CTSExtension.ts +17 -0
  27. package/src/core/extensions/Extension.ts +62 -0
  28. package/src/core/extensions/index.ts +9 -0
  29. package/src/core/hooks/componentHook.ts +40 -0
  30. package/src/core/hooks/index.ts +11 -0
  31. package/src/core/hooks/moduleHook.ts +39 -0
  32. package/src/core/index.ts +15 -0
  33. package/src/core/listener/index.ts +29 -0
  34. package/src/core/structures/CommandClient.ts +71 -0
  35. package/src/core/structures/Registry.ts +110 -0
  36. package/src/core/structures/index.ts +10 -0
  37. package/src/core/symbols.ts +13 -0
  38. package/src/core/utils/checks.ts +27 -0
  39. package/src/core/utils/errors.ts +9 -0
  40. package/src/core/utils/index.ts +10 -0
  41. package/src/index.ts +11 -16
  42. package/src/textCommand/TextCommand.ts +11 -0
  43. package/src/textCommand/index.ts +1 -0
  44. package/test/index.ts +74 -21
  45. package/tsconfig.json +3 -3
  46. package/tsconfig.prod.json +8 -0
  47. package/tsup.config.ts +9 -4
  48. package/src/applicationCommand/AppCommand.ts +0 -32
  49. package/src/applicationCommand/decorator.ts +0 -62
  50. package/src/builtinModules/BuiltInModule.ts +0 -13
  51. package/src/builtinModules/BuiltinApplicationCommandConverters.ts +0 -16
  52. package/src/builtinModules/BuiltinCommandConverters.ts +0 -87
  53. package/src/builtinModules/CommandHandler.ts +0 -363
  54. package/src/builtinModules/index.ts +0 -7
  55. package/src/command/ArgumentConverter.ts +0 -22
  56. package/src/command/Command.ts +0 -35
  57. package/src/command/cooldown/adapter.ts +0 -22
  58. package/src/command/cooldown/decorator.ts +0 -67
  59. package/src/command/cooldown/error.ts +0 -9
  60. package/src/command/cooldown/index.ts +0 -9
  61. package/src/command/cooldown/type.ts +0 -12
  62. package/src/command/decorator.ts +0 -185
  63. package/src/command/index.ts +0 -9
  64. package/src/command/utils.ts +0 -33
  65. package/src/constants.ts +0 -31
  66. package/src/error/ArgumentConverterNotFound.ts +0 -18
  67. package/src/error/ArgumentNotProvided.ts +0 -12
  68. package/src/error/CommandCheckFailed.ts +0 -19
  69. package/src/error/CommandNotFound.ts +0 -11
  70. package/src/error/InvalidTargetError.ts +0 -9
  71. package/src/error/ModuleError.ts +0 -11
  72. package/src/error/PermissionRequired.ts +0 -17
  73. package/src/error/checks/DMOnlyCommand.ts +0 -9
  74. package/src/error/checks/GuildOnlyCommand.ts +0 -9
  75. package/src/error/checks/OwnerOnlyCommand.ts +0 -9
  76. package/src/error/checks/SlashCommandGlobalCheckError.ts +0 -11
  77. package/src/error/checks/index.ts +0 -8
  78. package/src/error/index.ts +0 -12
  79. package/src/interface/index.ts +0 -7
  80. package/src/listener/Listener.ts +0 -7
  81. package/src/listener/decorator.ts +0 -29
  82. package/src/listener/index.ts +0 -6
  83. package/src/messageComponents/base.ts +0 -16
  84. package/src/messageComponents/button.ts +0 -30
  85. package/src/messageComponents/index.ts +0 -6
  86. package/src/messageComponents/selectMenu.ts +0 -30
  87. package/src/structures/CommandClient.ts +0 -103
  88. package/src/structures/Module.ts +0 -54
  89. package/src/structures/Registry.ts +0 -253
  90. package/src/structures/index.ts +0 -7
  91. package/src/typings.ts +0 -35
  92. package/src/utils.ts +0 -10
  93. package/test/config.example.json +0 -3
  94. package/test/modules/dev.ts +0 -45
  95. package/test/modules/test.ts +0 -148
@@ -1,363 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- import { BuiltInModule } from './BuiltInModule'
6
- import { Registry } from '../structures'
7
- import { listener } from '../listener'
8
- import {
9
- CommandInteraction,
10
- CommandInteractionOptionResolver,
11
- GuildMember,
12
- Interaction,
13
- Message,
14
- MessageComponentInteraction,
15
- MessageContextMenuInteraction,
16
- Role,
17
- User,
18
- UserContextMenuInteraction,
19
- } from 'discord.js'
20
- import { CommandClient } from '../structures'
21
- import { Command } from '../command'
22
- import { ArgumentConverterNotFound, ArgumentNotProvided, CommandCheckFailed, ApplicationCommandArgumentConverterNotFound, ApplicationCommandCheckFailed } from '../error'
23
- import { CommandNotFound } from '../error/CommandNotFound'
24
- import { SlashCommandGlobalCheckError } from '../error/checks/SlashCommandGlobalCheckError'
25
- import { MessageComponentHandler } from '../messageComponents/base'
26
-
27
- export class CommandHandler extends BuiltInModule {
28
- private readonly client: CommandClient
29
-
30
- constructor(private registry: Registry) {
31
- super()
32
- this.client = registry.client
33
- }
34
-
35
- // region message command handler
36
- @listener('messageCreate')
37
- async message(msg: Message) {
38
- const error = (error: Error) => this.client.client.emit('commandError', error, msg)
39
-
40
- try {
41
- const prefixList: string[] | string =
42
- typeof this.client.options.command.prefix === 'string'
43
- ? this.client.options.command.prefix
44
- : typeof this.client.options.command.prefix === 'function'
45
- ? await this.client.options.command.prefix(msg)
46
- : this.client.options.command.prefix
47
- let prefix: string
48
- if (typeof prefixList === 'object') {
49
- const res = prefixList.find((x) => msg.content.includes(x))
50
-
51
- if (!res) return
52
-
53
- prefix = res
54
- } else {
55
- if (!msg.content.includes(prefixList)) return
56
- prefix = prefixList
57
- }
58
-
59
- if (!msg.content.startsWith(prefix)) return
60
-
61
- const args = msg.content.slice(prefix.length).split(' ')
62
-
63
- const command = args.shift()
64
-
65
- if (!command) return
66
-
67
- let cmd: Command | null = null
68
-
69
- for (const c of this.registry.commands) {
70
- const aliases = typeof c.aliases === 'function' ? await c.aliases(msg) : c.aliases
71
- if ([...aliases, c.name].some((x) => x === command)) {
72
- cmd = c
73
- break
74
- }
75
- }
76
-
77
- msg.data = {
78
- cts: this.client,
79
- command: cmd,
80
- prefix: prefix,
81
- }
82
-
83
- if (!(await this.client.options.command.check(msg))) {
84
- return
85
- }
86
-
87
- if (!cmd) return error(new CommandNotFound(command, msg, args))
88
-
89
- const module = this.registry.modules.find((x) => x.commands.includes(cmd!))
90
-
91
- if (!module) return
92
-
93
- const argList: any[] = []
94
-
95
- for (const check of cmd.checks) {
96
- if (!(await check(msg))) return error(new CommandCheckFailed(msg, cmd))
97
- }
98
-
99
- for (let i = 0; i < cmd.argTypes.length; i++) {
100
- const argType = cmd.argTypes[i]
101
- const converter = this.registry.argumentConverters.find((x) => x.type === argType.type)
102
-
103
- if (argType.rest) {
104
- const i = args.join(' ')
105
- argList.push(i)
106
- break
107
- }
108
-
109
- if (!converter) return error(new ArgumentConverterNotFound(argType, msg))
110
-
111
- const converterModule = this.registry.modules.find((x) => x.argumentConverters.includes(converter))
112
-
113
- if (!converterModule) return error(new ArgumentConverterNotFound(argType, msg))
114
-
115
- if (converter.withoutParameter) {
116
- argList.push(await converter.execute(converterModule, msg))
117
- continue
118
- }
119
- const arg = args.shift()
120
- if (argType.optional && !arg) {
121
- break
122
- }
123
- if (!arg) {
124
- return error(new ArgumentNotProvided(i, cmd, msg))
125
- }
126
- const executed = await converter.execute(converterModule, msg, arg)
127
- if ((executed === undefined || executed === null) && !argType.optional) {
128
- return error(new ArgumentNotProvided(i, cmd, msg))
129
- }
130
- argList.push(executed)
131
- }
132
-
133
- try {
134
- await cmd.execute(module, argList)
135
- } catch (e: any) {
136
- return error(e)
137
- }
138
- } catch (e) {
139
- return error(e)
140
- }
141
- }
142
- // endregion
143
-
144
- // region slash command handler
145
- private async command(i: CommandInteraction) {
146
- const error = (error: Error) => this.client.client.emit('applicationCommandError', error, i)
147
- try {
148
- const cmd = this.registry.applicationCommands.find((x) => x.command.type === 'CHAT_INPUT' && x.command.name === i.commandName)
149
-
150
- if (!cmd) return
151
-
152
- const module = this.registry.modules.find((x) => x.applicationCommands.includes(cmd))
153
-
154
- if (!module) return
155
-
156
- const argList: any[] = []
157
-
158
- i.data = {
159
- cts: this.client,
160
- command: cmd,
161
- }
162
-
163
- if (!(await this.client.options.slashCommands.check(i))) {
164
- return error(new SlashCommandGlobalCheckError(i))
165
- }
166
- for (const check of cmd.checks) {
167
- if (!(await check(i))) return error(new ApplicationCommandCheckFailed(i, cmd))
168
- }
169
-
170
- for (let j = 0; j < cmd.params.length; j++) {
171
- const argType = cmd.params[j]
172
- const converter = this.registry.applicationCommandArgumentConverters.find((x) => x.type === argType.type)
173
-
174
- if (argType.type === CommandInteraction) {
175
- argList.push(i)
176
- continue
177
- }
178
-
179
- if (argType.type === CommandInteractionOptionResolver) {
180
- argList.push(i.options)
181
- continue
182
- }
183
-
184
- if (argType.name) {
185
- switch (argType.type) {
186
- case String:
187
- argList.push(i.options.getString(argType.name, false) || undefined)
188
- break
189
- case Role:
190
- argList.push(i.options.getRole(argType.name, false) || undefined)
191
- break
192
- case User:
193
- argList.push(i.options.getUser(argType.name, false) || undefined)
194
- break
195
- case GuildMember:
196
- argList.push(i.options.getMember(argType.name, false) || undefined)
197
- break
198
- case Boolean:
199
- argList.push(i.options.getBoolean(argType.name, false) || undefined)
200
- break
201
- case Number:
202
- const opt = i.options.get(argType.name, false)
203
- if (!opt) {
204
- argList.push(undefined)
205
- break
206
- }
207
- if (opt.type == 'NUMBER') {
208
- argList.push(i.options.getNumber(argType.name, false) ?? undefined)
209
- break
210
- }
211
- if (opt.type == 'INTEGER') {
212
- argList.push(i.options.getInteger(argType.name, false) ?? undefined)
213
- break
214
- }
215
- }
216
- continue
217
- }
218
-
219
- if (!converter) return error(new ApplicationCommandArgumentConverterNotFound(argType, i))
220
-
221
- argList.push(await converter.execute(module, i))
222
- }
223
-
224
- await cmd.execute(module, argList)
225
- } catch (e) {
226
- return error(e)
227
- }
228
- }
229
- // endregion
230
-
231
- private async messageComponent(i: MessageComponentInteraction) {
232
- const error = (e: any) => this.client.client.emit('messageComponentError', e)
233
-
234
- try {
235
- const handlers: MessageComponentHandler[] = []
236
-
237
- for (const handler of this.registry.messageComponentHandlers) {
238
- if (handler.componentId === handler.componentId && handler.componentType === i.componentType) {
239
- handlers.push(handler)
240
- }
241
- }
242
-
243
- for (const handler of handlers) {
244
- const module = this.registry.modules.find((x) => x.messageComponentHandlers.includes(handler))
245
- if (!module) continue
246
- await handler.run(module, i)
247
- }
248
- } catch (e) {
249
- error(e)
250
- }
251
- }
252
-
253
- private async userContextMenu(i: UserContextMenuInteraction) {
254
- const error = (error: Error) => this.client.client.emit('applicationCommandError', error, i)
255
- try {
256
- const cmd = this.registry.applicationCommands.find((x) => x.command.type === 'USER' && x.command.name === i.commandName)
257
-
258
- if (!cmd) return
259
-
260
- const module = this.registry.modules.find((x) => x.applicationCommands.includes(cmd))
261
-
262
- if (!module) return
263
-
264
- i.data = {
265
- cts: this.client,
266
- command: cmd,
267
- }
268
-
269
- for (const check of cmd.checks) {
270
- if (!(await check(i))) return error(new ApplicationCommandCheckFailed(i, cmd))
271
- }
272
-
273
- let argList: any[] = []
274
-
275
- for (let j = 0; j < cmd.params.length; j++) {
276
- const argType = cmd.params[j]
277
- const converter = this.registry.applicationCommandArgumentConverters.find((x) => x.type === argType.type)
278
-
279
- if (argType.type === UserContextMenuInteraction) {
280
- argList.push(i)
281
- continue
282
- }
283
-
284
- if (!converter) return error(new ApplicationCommandArgumentConverterNotFound(argType, i))
285
-
286
- argList.push(await converter.execute(module, i))
287
- }
288
-
289
- await cmd.execute(module, argList)
290
- } catch (e) {
291
- return error(e)
292
- }
293
- }
294
-
295
- private async messageContextMenu(i: MessageContextMenuInteraction) {
296
- const error = (error: Error) => this.client.client.emit('applicationCommandError', error, i)
297
- try {
298
- const cmd = this.registry.applicationCommands.find((x) => x.command.type === 'MESSAGE' && x.command.name === i.commandName)
299
-
300
- if (!cmd) return
301
-
302
- const module = this.registry.modules.find((x) => x.applicationCommands.includes(cmd))
303
-
304
- if (!module) return
305
-
306
- i.data = {
307
- cts: this.client,
308
- command: cmd,
309
- }
310
-
311
- for (const check of cmd.checks) {
312
- if (!(await check(i))) return error(new ApplicationCommandCheckFailed(i, cmd))
313
- }
314
-
315
- let argList: any[] = []
316
-
317
- for (let j = 0; j < cmd.params.length; j++) {
318
- const argType = cmd.params[j]
319
- const converter = this.registry.applicationCommandArgumentConverters.find((x) => x.type === argType.type)
320
-
321
- if (argType.type === MessageContextMenuInteraction) {
322
- argList.push(i)
323
- continue
324
- }
325
-
326
- if (!converter) return error(new ApplicationCommandArgumentConverterNotFound(argType, i))
327
-
328
- argList.push(await converter.execute(module, i))
329
- }
330
-
331
- await cmd.execute(module, argList)
332
- } catch (e) {
333
- return error(e)
334
- }
335
- }
336
-
337
- @listener('interactionCreate')
338
- async interaction(i: Interaction) {
339
- const error = (e: any) => this.client.client.emit('interactionError', e, i)
340
-
341
- try {
342
- await this.client.options.applicationCommands.beforeRunCheck(i)
343
- if (i.isCommand()) {
344
- await this.command(i)
345
- return
346
- }
347
- if (i.isMessageComponent()) {
348
- await this.messageComponent(i)
349
- return
350
- }
351
- if (i.isMessageContextMenu()) {
352
- await this.messageContextMenu(i)
353
- return
354
- }
355
- if (i.isUserContextMenu()) {
356
- await this.userContextMenu(i)
357
- return
358
- }
359
- } catch (e) {
360
- return error(e)
361
- }
362
- }
363
- }
@@ -1,7 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- export * from './CommandHandler'
6
- export * from './BuiltinCommandConverters'
7
- export * from './BuiltinApplicationCommandConverters'
@@ -1,22 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- import { Module } from '../structures'
6
- import { CommandInteraction, ContextMenuInteraction, Message } from 'discord.js'
7
-
8
- export class ArgumentConverter {
9
- execute(module: Module, msg: Message, arg?: string) {
10
- return this.run.apply(module, [msg, arg])
11
- }
12
-
13
- constructor(public type: object, private run: Function, public withoutParameter: boolean) {}
14
- }
15
-
16
- export class ApplicationCommandArgumentConverter {
17
- execute(module: Module, interaction: CommandInteraction | ContextMenuInteraction) {
18
- return this.run.apply(module, [interaction])
19
- }
20
-
21
- constructor(public type: object, private run: Function) {}
22
- }
@@ -1,35 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- import { Module } from '../structures'
6
- import { CommandInteraction, ContextMenuInteraction, Message, MessageComponentInteraction } from 'discord.js'
7
- import { KCommandChecks } from '../constants'
8
-
9
- export type Argument = {
10
- optional: boolean
11
- type: any
12
- rest: boolean
13
- }
14
-
15
- export type CheckFunction = (msg: Message) => boolean | Promise<boolean>
16
- export type ApplicationCommandCheckFunction = (i: CommandInteraction | MessageComponentInteraction | ContextMenuInteraction) => boolean | Promise<boolean>
17
-
18
- export class Command {
19
- execute(module: Module, args: any[]) {
20
- return this.run.apply(module, args)
21
- }
22
-
23
- get checks(): CheckFunction[] {
24
- return Reflect.getMetadata(KCommandChecks, this.module, this.key) || []
25
- }
26
-
27
- constructor(
28
- private run: Function,
29
- public argTypes: Argument[],
30
- public name: string,
31
- public aliases: string[] | ((msg: Message) => string[] | Promise<string[]>),
32
- public module: Module,
33
- public key: symbol | string,
34
- ) {}
35
- }
@@ -1,22 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- import { Collection } from 'discord.js'
6
-
7
- export interface CoolDownAdapter {
8
- get(id: string): Promise<number | undefined>
9
- set(id: string, value: number): Promise<void>
10
- }
11
-
12
- export class DefaultCoolDownAdapter implements CoolDownAdapter {
13
- map = new Collection<string, number>()
14
- async get(id: string): Promise<number | undefined> {
15
- return this.map.get(id)
16
- }
17
-
18
- async set(id: string, value: number) {
19
- this.map.set(id, value)
20
- return
21
- }
22
- }
@@ -1,67 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- import { createCheckDecorator } from '../utils'
6
- import { CoolDownType } from './type'
7
- import { DMChannel, GuildMember, TextChannel } from 'discord.js'
8
- import { CoolDownError } from './error'
9
-
10
- export const coolDown = (type: CoolDownType, seconds: number) =>
11
- createCheckDecorator(
12
- async (msg) => {
13
- const a = msg.data.cts.coolDownAdapter
14
- const getKey = (): string => {
15
- switch (type) {
16
- case CoolDownType.USER:
17
- return msg.author.id
18
- case CoolDownType.GUILD:
19
- return (msg.guild || msg.author).id
20
- case CoolDownType.CHANNEL:
21
- return msg.channel.id
22
- case CoolDownType.MEMBER:
23
- return `${msg.guild?.id}.${msg.author.id}`
24
- case CoolDownType.ROLE:
25
- return (msg.channel instanceof DMChannel ? msg.channel : msg.member!.roles.highest).id
26
- case CoolDownType.CATEGORY:
27
- return ((msg.channel as TextChannel).parent || msg.channel).id
28
- }
29
- }
30
- const key = getKey() + '-command-' + msg.data.command?.name
31
- const data = await a.get(key)
32
- const now = Date.now()
33
- if (!data || !(now - data < seconds * 1000)) {
34
- await a.set(key, now)
35
- return true
36
- }
37
- throw new CoolDownError(new Date(data + seconds * 1000))
38
- },
39
- async (i) => {
40
- if (i.isMessageComponent()) return true
41
- const a = i.data.cts.coolDownAdapter
42
- const getKey = (): string => {
43
- switch (type) {
44
- case CoolDownType.USER:
45
- return i.user.id + '.user'
46
- case CoolDownType.GUILD:
47
- return (i.guild || i.user).id + '.guild'
48
- case CoolDownType.CHANNEL:
49
- return i.channel!.id + '.channel'
50
- case CoolDownType.MEMBER:
51
- return `${i.guild?.id}.${i.user.id}`
52
- case CoolDownType.ROLE:
53
- return (i.channel instanceof DMChannel ? i.channel : (i.member as GuildMember)!.roles.highest).id + '.role'
54
- case CoolDownType.CATEGORY:
55
- return ((i.channel as TextChannel).parent || i.channel!).id + '.category'
56
- }
57
- }
58
- const key = getKey() + '-appCommand-' + i.commandName
59
- const data = await a.get(key)
60
- const now = Date.now()
61
- if (!data || !(now - data < seconds * 1000)) {
62
- await a.set(key, now)
63
- return true
64
- }
65
- throw new CoolDownError(new Date(data + seconds * 1000))
66
- },
67
- )
@@ -1,9 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- export class CoolDownError extends Error {
6
- constructor(public endsAt: Date) {
7
- super()
8
- }
9
- }
@@ -1,9 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- export * from './decorator'
6
- export * from './adapter'
7
- export * from './decorator'
8
- export * from './error'
9
- export * from './type'
@@ -1,12 +0,0 @@
1
- /*
2
- * Copyright (c) 2022 pikokr. Licensed under the MIT license
3
- */
4
-
5
- export enum CoolDownType {
6
- USER,
7
- CHANNEL,
8
- GUILD,
9
- ROLE,
10
- CATEGORY,
11
- MEMBER,
12
- }