@pikokr/command.ts 4.0.7 → 5.0.0-dev.144e990
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/.github/workflows/codeql-analysis.yml +70 -0
- package/.github/workflows/docs.yml +2 -2
- package/.github/workflows/publish.stable.yml +1 -1
- package/.github/workflows/publish.yml +1 -1
- package/.vscode/settings.json +10 -0
- package/.vscode/templates/ts.lict +5 -0
- package/README.md +2 -0
- package/dist/index.d.ts +140 -292
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/docs/index.yml +1 -1
- package/package.json +22 -16
- package/publish-version.js +20 -0
- package/renovate.json +5 -0
- package/scripts/docs.ts +8 -4
- package/src/applicationCommand/ApplicationCommand.ts +17 -0
- package/src/applicationCommand/ApplicationCommandExtension.ts +169 -0
- package/src/applicationCommand/ApplicationCommandOption.ts +16 -0
- package/src/applicationCommand/index.ts +10 -6
- package/src/core/components/BaseComponent.ts +62 -0
- package/src/core/components/ComponentArgument.ts +15 -0
- package/src/core/components/ComponentArgumentDecorator.ts +25 -0
- package/src/core/components/decoratorCreator.ts +81 -0
- package/src/core/components/index.ts +13 -0
- package/src/core/converter/index.ts +16 -0
- package/src/core/extensions/CTSExtension.ts +17 -0
- package/src/core/extensions/Extension.ts +62 -0
- package/src/core/extensions/index.ts +9 -0
- package/src/core/hooks/componentHook.ts +40 -0
- package/src/core/hooks/index.ts +11 -0
- package/src/core/hooks/moduleHook.ts +39 -0
- package/src/core/index.ts +15 -0
- package/src/core/listener/index.ts +29 -0
- package/src/core/structures/CommandClient.ts +78 -0
- package/src/core/structures/Registry.ts +110 -0
- package/src/core/structures/index.ts +10 -0
- package/src/core/symbols.ts +13 -0
- package/src/core/utils/checks.ts +27 -0
- package/src/core/utils/errors.ts +9 -0
- package/src/core/utils/index.ts +10 -0
- package/src/index.ts +11 -16
- package/src/textCommand/TextCommand.ts +20 -0
- package/src/textCommand/TextCommandExtension.ts +128 -0
- package/src/textCommand/index.ts +11 -0
- package/src/textCommand/parameters.ts +14 -0
- package/test/index.ts +85 -20
- package/tsconfig.json +3 -3
- package/tsconfig.prod.json +8 -0
- package/tsup.config.ts +9 -4
- package/src/applicationCommand/AppCommand.ts +0 -32
- package/src/applicationCommand/decorator.ts +0 -62
- package/src/builtinModules/BuiltInModule.ts +0 -13
- package/src/builtinModules/BuiltinApplicationCommandConverters.ts +0 -16
- package/src/builtinModules/BuiltinCommandConverters.ts +0 -87
- package/src/builtinModules/CommandHandler.ts +0 -363
- package/src/builtinModules/index.ts +0 -7
- package/src/command/ArgumentConverter.ts +0 -22
- package/src/command/Command.ts +0 -35
- package/src/command/cooldown/adapter.ts +0 -22
- package/src/command/cooldown/decorator.ts +0 -67
- package/src/command/cooldown/error.ts +0 -9
- package/src/command/cooldown/index.ts +0 -9
- package/src/command/cooldown/type.ts +0 -12
- package/src/command/decorator.ts +0 -185
- package/src/command/index.ts +0 -9
- package/src/command/utils.ts +0 -33
- package/src/constants.ts +0 -31
- package/src/error/ArgumentConverterNotFound.ts +0 -18
- package/src/error/ArgumentNotProvided.ts +0 -12
- package/src/error/CommandCheckFailed.ts +0 -19
- package/src/error/CommandNotFound.ts +0 -11
- package/src/error/InvalidTargetError.ts +0 -9
- package/src/error/ModuleError.ts +0 -11
- package/src/error/PermissionRequired.ts +0 -17
- package/src/error/checks/DMOnlyCommand.ts +0 -9
- package/src/error/checks/GuildOnlyCommand.ts +0 -9
- package/src/error/checks/OwnerOnlyCommand.ts +0 -9
- package/src/error/checks/SlashCommandGlobalCheckError.ts +0 -11
- package/src/error/checks/index.ts +0 -8
- package/src/error/index.ts +0 -12
- package/src/interface/index.ts +0 -7
- package/src/listener/Listener.ts +0 -7
- package/src/listener/decorator.ts +0 -29
- package/src/listener/index.ts +0 -6
- package/src/messageComponents/base.ts +0 -16
- package/src/messageComponents/button.ts +0 -30
- package/src/messageComponents/index.ts +0 -6
- package/src/messageComponents/selectMenu.ts +0 -30
- package/src/structures/CommandClient.ts +0 -103
- package/src/structures/Module.ts +0 -54
- package/src/structures/Registry.ts +0 -253
- package/src/structures/index.ts +0 -7
- package/src/typings.ts +0 -35
- package/src/utils.ts +0 -10
- package/test/config.example.json +0 -3
- package/test/modules/dev.ts +0 -44
- package/test/modules/test.ts +0 -148
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: ApplicationCommandExtension.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import chalk from 'chalk'
|
|
10
|
+
import {
|
|
11
|
+
ApplicationCommandData,
|
|
12
|
+
ApplicationCommandType,
|
|
13
|
+
ChatInputCommandInteraction,
|
|
14
|
+
Interaction,
|
|
15
|
+
InteractionType,
|
|
16
|
+
MessageContextMenuCommandInteraction,
|
|
17
|
+
Snowflake,
|
|
18
|
+
UserContextMenuCommandInteraction,
|
|
19
|
+
} from 'discord.js'
|
|
20
|
+
import { ApplicationCommandComponent } from './ApplicationCommand'
|
|
21
|
+
import { ApplicationCommandOption } from './ApplicationCommandOption'
|
|
22
|
+
import { moduleHook } from '../core/hooks'
|
|
23
|
+
import { listener } from '../core/listener'
|
|
24
|
+
import { CommandClient } from '../core/structures'
|
|
25
|
+
import { argConverter } from '../core/converter'
|
|
26
|
+
import { CTSExtension } from '../core/extensions/CTSExtension'
|
|
27
|
+
|
|
28
|
+
export type ApplicationCommandExtensionConfig = {
|
|
29
|
+
guilds?: Snowflake[]
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export class ApplicationCommandExtension extends CTSExtension {
|
|
33
|
+
constructor(public config: ApplicationCommandExtensionConfig) {
|
|
34
|
+
super()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
@listener({ event: 'interactionCreate' })
|
|
38
|
+
async interactionCreate(i: Interaction) {
|
|
39
|
+
if (i.type !== InteractionType.ApplicationCommand) return
|
|
40
|
+
|
|
41
|
+
let cmd: ApplicationCommandComponent | null = null
|
|
42
|
+
let ext: object | null = null
|
|
43
|
+
|
|
44
|
+
const extensions = this.commandClient.registry.extensions
|
|
45
|
+
|
|
46
|
+
for (const extension of extensions) {
|
|
47
|
+
const components = this.commandClient.registry.getComponentsWithType(extension, ApplicationCommandComponent)
|
|
48
|
+
|
|
49
|
+
for (const command of components) {
|
|
50
|
+
if (command.options.name === i.commandName) {
|
|
51
|
+
ext = extension
|
|
52
|
+
cmd = command
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (cmd && ext) {
|
|
58
|
+
const argList: unknown[] = []
|
|
59
|
+
|
|
60
|
+
await this.convertArguments(ApplicationCommandComponent, argList, cmd.argTypes, () => [i])
|
|
61
|
+
|
|
62
|
+
for (const [idx, arg] of cmd.argTypes) {
|
|
63
|
+
let value: unknown = null
|
|
64
|
+
|
|
65
|
+
for (const decorator of arg.decorators) {
|
|
66
|
+
if (decorator instanceof ApplicationCommandOption) {
|
|
67
|
+
value = i.options.get(decorator.options.name, false)?.value
|
|
68
|
+
break
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (value) {
|
|
73
|
+
argList[idx] = value
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
await cmd.execute(ext, argList, [i])
|
|
79
|
+
} catch (e) {
|
|
80
|
+
this.logger.error(e)
|
|
81
|
+
this.commandClient.emit('applicationCommandInvokeError', e, i)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
@moduleHook('load')
|
|
87
|
+
async load() {}
|
|
88
|
+
|
|
89
|
+
async sync() {
|
|
90
|
+
const client = CommandClient.getFromModule(this)
|
|
91
|
+
|
|
92
|
+
this.logger.info('Trying to sync commands...')
|
|
93
|
+
|
|
94
|
+
const commands: ApplicationCommandData[] = []
|
|
95
|
+
|
|
96
|
+
for (const command of client.registry.getComponentsWithTypeGlobal(ApplicationCommandComponent)) {
|
|
97
|
+
const cmd: ApplicationCommandData = { ...command.options }
|
|
98
|
+
|
|
99
|
+
if (cmd.type === ApplicationCommandType.ChatInput) {
|
|
100
|
+
cmd.options = []
|
|
101
|
+
|
|
102
|
+
for (const [, arg] of command.argTypes) {
|
|
103
|
+
const option = arg.decorators.find((x) => x.constructor === ApplicationCommandOption) as ApplicationCommandOption
|
|
104
|
+
|
|
105
|
+
if (option) {
|
|
106
|
+
cmd.options.push(option.options)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
commands.push(cmd)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
this.logger.info(`Processing ${chalk.green(commands.length)} commands(${commands.map((x) => chalk.blue(x.name)).join(', ')})`)
|
|
115
|
+
|
|
116
|
+
if (this.config.guilds) {
|
|
117
|
+
for (const guild of this.config.guilds) {
|
|
118
|
+
try {
|
|
119
|
+
const g = await this.client.guilds.fetch(guild)
|
|
120
|
+
await g.fetch()
|
|
121
|
+
this.logger.info(`Registering commands for guild ${chalk.green(g.name)}(${chalk.blue(g.id)})`)
|
|
122
|
+
|
|
123
|
+
await g.commands.set(commands)
|
|
124
|
+
|
|
125
|
+
this.logger.info(`Successfully registered commands for guild ${chalk.green(g.name)}(${chalk.blue(g.id)})`)
|
|
126
|
+
} catch (e) {
|
|
127
|
+
this.logger.error(`Failed to register commands to guild ${chalk.green(guild)}: ${(e as Error).message}`)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
} else {
|
|
131
|
+
try {
|
|
132
|
+
this.logger.info(`Registering commands globally...`)
|
|
133
|
+
|
|
134
|
+
await this.client.application!.commands.set(commands)
|
|
135
|
+
|
|
136
|
+
this.logger.info('Successfully registered commands.')
|
|
137
|
+
} catch (e) {
|
|
138
|
+
this.logger.error(`Failed to register commands to global: ${(e as Error).message}`)
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@argConverter({
|
|
144
|
+
component: ApplicationCommandComponent,
|
|
145
|
+
parameterless: true,
|
|
146
|
+
type: ChatInputCommandInteraction,
|
|
147
|
+
})
|
|
148
|
+
async chatInteraction(i: ChatInputCommandInteraction) {
|
|
149
|
+
return i
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@argConverter({
|
|
153
|
+
component: ApplicationCommandComponent,
|
|
154
|
+
parameterless: true,
|
|
155
|
+
type: MessageContextMenuCommandInteraction,
|
|
156
|
+
})
|
|
157
|
+
async messageInteraction(i: MessageContextMenuCommandInteraction) {
|
|
158
|
+
return i
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@argConverter({
|
|
162
|
+
component: ApplicationCommandComponent,
|
|
163
|
+
parameterless: true,
|
|
164
|
+
type: UserContextMenuCommandInteraction,
|
|
165
|
+
})
|
|
166
|
+
async userInteraction(i: UserContextMenuCommandInteraction) {
|
|
167
|
+
return i
|
|
168
|
+
}
|
|
169
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: ApplicationCommandOption.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { APIApplicationCommandOption } from 'discord.js'
|
|
10
|
+
import { createArgumentDecorator, ComponentArgumentDecorator } from '../core'
|
|
11
|
+
|
|
12
|
+
type Options = APIApplicationCommandOption
|
|
13
|
+
|
|
14
|
+
export class ApplicationCommandOption extends ComponentArgumentDecorator<Options> {}
|
|
15
|
+
|
|
16
|
+
export const option = createArgumentDecorator(ApplicationCommandOption)
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
/*
|
|
2
|
+
* File: index.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export * from './ApplicationCommand'
|
|
10
|
+
export { option } from './ApplicationCommandOption'
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: BaseComponent.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Collection } from 'discord.js'
|
|
10
|
+
import _ from 'lodash'
|
|
11
|
+
import type { ComponentHookStore } from '../hooks'
|
|
12
|
+
import { ComponentArgument } from './ComponentArgument'
|
|
13
|
+
|
|
14
|
+
export class BaseComponent<Options = unknown, OptionsArg = Options> {
|
|
15
|
+
options: Options
|
|
16
|
+
|
|
17
|
+
method: Function
|
|
18
|
+
|
|
19
|
+
hooks: ComponentHookStore = new Collection()
|
|
20
|
+
|
|
21
|
+
argTypes: Collection<number, ComponentArgument> = new Collection()
|
|
22
|
+
|
|
23
|
+
constructor(options: OptionsArg, method: Function, argTypes: unknown[]) {
|
|
24
|
+
this.options = this.convertOptions(options)
|
|
25
|
+
|
|
26
|
+
this.method = method
|
|
27
|
+
for (let i = 0; i < argTypes.length; i++) {
|
|
28
|
+
const element = argTypes[i]
|
|
29
|
+
this.argTypes.set(i, new ComponentArgument(element))
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
convertOptions(options: OptionsArg): Options {
|
|
34
|
+
return options as unknown as Options
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async executeHook(target: object, name: string, args: unknown[]) {
|
|
38
|
+
const hook = this.hooks.get(name)
|
|
39
|
+
|
|
40
|
+
if (!hook) return
|
|
41
|
+
|
|
42
|
+
const { CommandClient } = await import('../structures/CommandClient')
|
|
43
|
+
|
|
44
|
+
for (const fn of hook) {
|
|
45
|
+
await fn.call(null, CommandClient.getFromModule(target), ...args)
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async execute(target: object, args: unknown[], beforeCallArgs: unknown[] = args) {
|
|
50
|
+
await this.executeHook(target, 'beforeCall', beforeCallArgs)
|
|
51
|
+
let result
|
|
52
|
+
try {
|
|
53
|
+
result = await this.method.call(target, ...args)
|
|
54
|
+
} catch (e) {
|
|
55
|
+
await this.executeHook(target, 'invokeError', [e])
|
|
56
|
+
throw e
|
|
57
|
+
}
|
|
58
|
+
await this.executeHook(target, 'afterCall', [result])
|
|
59
|
+
|
|
60
|
+
return result
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: ComponentArgument.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ComponentArgumentDecorator } from './ComponentArgumentDecorator'
|
|
10
|
+
|
|
11
|
+
export class ComponentArgument {
|
|
12
|
+
decorators: ComponentArgumentDecorator[] = []
|
|
13
|
+
|
|
14
|
+
constructor(public type: unknown) {}
|
|
15
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: ComponentArgumentDecorator.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import _ from 'lodash'
|
|
10
|
+
|
|
11
|
+
export class ComponentArgumentDecorator<Options = unknown> {
|
|
12
|
+
options: Options
|
|
13
|
+
|
|
14
|
+
constructor(options: Partial<Options>) {
|
|
15
|
+
if (typeof options === 'object') {
|
|
16
|
+
this.options = _.merge(this.defaultOptions(), options)
|
|
17
|
+
} else {
|
|
18
|
+
this.options = options
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
defaultOptions(): Options {
|
|
23
|
+
return {} as unknown as Options
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: decoratorCreator.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Collection } from 'discord.js'
|
|
10
|
+
import { ComponentHookStore } from '../hooks'
|
|
11
|
+
import { getComponentHookStore } from '../hooks/componentHook'
|
|
12
|
+
import { ComponentStoreSymbol } from '../symbols'
|
|
13
|
+
import { BaseComponent } from './BaseComponent'
|
|
14
|
+
import { ComponentArgumentDecorator } from './ComponentArgumentDecorator'
|
|
15
|
+
|
|
16
|
+
type ComponentStore = Collection<string | symbol, BaseComponent>
|
|
17
|
+
type ComponentArgumentStore = Collection<number, ComponentArgumentDecorator>
|
|
18
|
+
|
|
19
|
+
export const getComponentStore = (target: object): ComponentStore => {
|
|
20
|
+
let result: ComponentStore | null = Reflect.getMetadata(ComponentStoreSymbol, target)
|
|
21
|
+
|
|
22
|
+
if (!result) {
|
|
23
|
+
result = new Collection()
|
|
24
|
+
|
|
25
|
+
Reflect.defineMetadata(ComponentStoreSymbol, result, target)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return result
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const getComponent = (target: object, key: string | symbol) => {
|
|
32
|
+
const store = getComponentStore(target)
|
|
33
|
+
|
|
34
|
+
return store.get(key)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export const createComponentDecorator = <Options, OptionArgs>(type: typeof BaseComponent<Options, OptionArgs>) => {
|
|
38
|
+
return (options: OptionArgs): MethodDecorator => {
|
|
39
|
+
return (target, key) => {
|
|
40
|
+
var component: BaseComponent<Options, OptionArgs> = new type(options, Reflect.get(target, key), Reflect.getMetadata('design:paramtypes', target, key))
|
|
41
|
+
|
|
42
|
+
const componentHookStore: ComponentHookStore = getComponentHookStore(target, key)
|
|
43
|
+
|
|
44
|
+
component.hooks = componentHookStore
|
|
45
|
+
|
|
46
|
+
const store = getComponentStore(target)
|
|
47
|
+
|
|
48
|
+
const decorators = getComponentArgumentStore(target, key)
|
|
49
|
+
|
|
50
|
+
decorators.forEach((x, i) => {
|
|
51
|
+
component.argTypes.get(i)?.decorators.push(x)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
store.set(key, component)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const getComponentArgumentStore = (target: object, key: string | symbol): ComponentArgumentStore => {
|
|
60
|
+
let result: ComponentArgumentStore | null = Reflect.getMetadata(ComponentStoreSymbol, target, key)
|
|
61
|
+
|
|
62
|
+
if (!result) {
|
|
63
|
+
result = new Collection()
|
|
64
|
+
|
|
65
|
+
Reflect.defineMetadata(ComponentStoreSymbol, result, target, key)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return result
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const createArgumentDecorator = <Options>(type: typeof ComponentArgumentDecorator<Options>) => {
|
|
72
|
+
return (options: Options): ParameterDecorator => {
|
|
73
|
+
return (target, key, idx) => {
|
|
74
|
+
var arg: ComponentArgumentDecorator<Options> = new type(options)
|
|
75
|
+
|
|
76
|
+
const store = getComponentArgumentStore(target, key)
|
|
77
|
+
|
|
78
|
+
store.set(idx, arg)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: index.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import 'reflect-metadata'
|
|
10
|
+
export * from './decoratorCreator'
|
|
11
|
+
export * from './ComponentArgument'
|
|
12
|
+
export * from './ComponentArgumentDecorator'
|
|
13
|
+
export * from './BaseComponent'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: index.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { BaseComponent } from '../components/BaseComponent'
|
|
10
|
+
import { createComponentDecorator } from '../components/decoratorCreator'
|
|
11
|
+
|
|
12
|
+
type Options = { component: typeof BaseComponent<unknown>; type: Function; parameterless: boolean }
|
|
13
|
+
|
|
14
|
+
export class ConverterComponent extends BaseComponent<Options, Omit<Options, 'parameterless'> & { parameterless?: boolean }> {}
|
|
15
|
+
|
|
16
|
+
export const argConverter = createComponentDecorator(ConverterComponent)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: CTSExtension.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import chalk from 'chalk'
|
|
10
|
+
import { Extension } from './Extension'
|
|
11
|
+
|
|
12
|
+
export class CTSExtension extends Extension {
|
|
13
|
+
protected get logger() {
|
|
14
|
+
if (!this._logger) this._logger = this.commandClient.ctsLogger.getChildLogger({ prefix: [chalk.green(`[${this.constructor.name}]`)], displayFunctionName: false })
|
|
15
|
+
return this._logger
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: Extension.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import chalk from 'chalk'
|
|
10
|
+
import { Collection } from 'discord.js'
|
|
11
|
+
import { Logger } from 'tslog'
|
|
12
|
+
import { BaseComponent } from '../components'
|
|
13
|
+
import { ComponentArgument } from '../components/ComponentArgument'
|
|
14
|
+
import { ConverterComponent } from '../converter'
|
|
15
|
+
import { CommandClient } from '../structures'
|
|
16
|
+
|
|
17
|
+
export class Extension {
|
|
18
|
+
protected get commandClient() {
|
|
19
|
+
return CommandClient.getFromModule(this)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
protected get client() {
|
|
23
|
+
return this.commandClient.discord
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
protected _logger?: Logger
|
|
27
|
+
|
|
28
|
+
protected get logger() {
|
|
29
|
+
if (!this._logger) this._logger = this.commandClient.logger.getChildLogger({ prefix: [chalk.green(`[${this.constructor.name}]`)], displayFunctionName: false })
|
|
30
|
+
return this._logger
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
protected async convertArguments(
|
|
34
|
+
component: typeof BaseComponent<unknown>,
|
|
35
|
+
argList: unknown[],
|
|
36
|
+
args: Collection<number, ComponentArgument>,
|
|
37
|
+
getConverterArgs: (arg: ComponentArgument, index: number, converter: ConverterComponent) => unknown[] | Promise<unknown[]>,
|
|
38
|
+
) {
|
|
39
|
+
const items = new Collection<unknown, { ext: object; component: ConverterComponent }>()
|
|
40
|
+
|
|
41
|
+
for (const extension of this.commandClient.registry.extensions) {
|
|
42
|
+
for (const converter of this.commandClient.registry.getComponentsWithType(extension, ConverterComponent)) {
|
|
43
|
+
if (converter.options.component != component) continue
|
|
44
|
+
|
|
45
|
+
items.set(converter.options.type, { component: converter, ext: extension })
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
for (const [index, arg] of args) {
|
|
50
|
+
const converter = items.get(arg.type)
|
|
51
|
+
|
|
52
|
+
if (!converter) {
|
|
53
|
+
argList[index] = undefined
|
|
54
|
+
continue
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const converterArgs = await getConverterArgs(arg, index, converter.component)
|
|
58
|
+
|
|
59
|
+
argList[index] = await converter.component.execute(converter.ext, converterArgs)
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: componentHook.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Collection } from 'discord.js'
|
|
10
|
+
import { ComponentHookSymbol } from '../symbols'
|
|
11
|
+
|
|
12
|
+
export type ComponentHookFn = (...args: any[]) => void | Promise<void>
|
|
13
|
+
|
|
14
|
+
export type ComponentHookStore = Collection<string, ComponentHookFn[]>
|
|
15
|
+
|
|
16
|
+
export const getComponentHookStore = (target: object, property: string | symbol): ComponentHookStore => {
|
|
17
|
+
let data = Reflect.getMetadata(ComponentHookSymbol, target, property) as ComponentHookStore
|
|
18
|
+
|
|
19
|
+
if (!data) {
|
|
20
|
+
data = new Collection()
|
|
21
|
+
Reflect.defineMetadata(ComponentHookSymbol, data, target, property)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return data
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const createComponentHook = (name: string, fn: ComponentHookFn): MethodDecorator => {
|
|
28
|
+
return (target, key) => {
|
|
29
|
+
const store = getComponentHookStore(target, key)
|
|
30
|
+
|
|
31
|
+
let hooks = store.get(name)
|
|
32
|
+
|
|
33
|
+
if (!hooks) {
|
|
34
|
+
hooks = []
|
|
35
|
+
store.set(name, hooks)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
hooks.push(fn)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: index.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export * from './moduleHook'
|
|
10
|
+
export { createComponentHook } from './componentHook'
|
|
11
|
+
export type { ComponentHookStore } from './componentHook'
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: moduleHook.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { Collection } from 'discord.js'
|
|
10
|
+
import { ModuleHookStoreSymbol } from '../symbols'
|
|
11
|
+
|
|
12
|
+
type ModuleHookStore = Collection<string, Function[]>
|
|
13
|
+
|
|
14
|
+
export const getModuleHookStore = (target: object) => {
|
|
15
|
+
let result: ModuleHookStore | null = Reflect.getMetadata(ModuleHookStoreSymbol, target)
|
|
16
|
+
|
|
17
|
+
if (!result) {
|
|
18
|
+
result = new Collection()
|
|
19
|
+
|
|
20
|
+
Reflect.defineMetadata(ModuleHookStoreSymbol, result, target)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return result
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const moduleHook = (name: string): MethodDecorator => {
|
|
27
|
+
return (target, key) => {
|
|
28
|
+
const store = getModuleHookStore(target)
|
|
29
|
+
|
|
30
|
+
let v = store.get(name)
|
|
31
|
+
|
|
32
|
+
if (!v) {
|
|
33
|
+
v = []
|
|
34
|
+
store.set(name, v)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
v.push(Reflect.get(target, key))
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: index.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export * from './components'
|
|
10
|
+
export * from './hooks'
|
|
11
|
+
export * from './converter'
|
|
12
|
+
export * from './utils'
|
|
13
|
+
export * from './listener'
|
|
14
|
+
export * from './structures'
|
|
15
|
+
export * from './extensions'
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: index.ts
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2022-2022 pikokr
|
|
5
|
+
*
|
|
6
|
+
* Licensed under MIT License. Please see more defails in LICENSE file.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { BaseComponent } from '../components/BaseComponent'
|
|
10
|
+
import { createComponentDecorator } from '../components/decoratorCreator'
|
|
11
|
+
|
|
12
|
+
export class ListenerComponent extends BaseComponent<{ emitter: string; event: string }, { emitter?: string; event: string }> {
|
|
13
|
+
defaultOptions() {
|
|
14
|
+
return { emitter: 'discord' }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
constructor(options: ListenerComponent['options'], method: Function, argTypes: unknown[]) {
|
|
18
|
+
super(
|
|
19
|
+
{
|
|
20
|
+
event: options.event,
|
|
21
|
+
emitter: options.emitter ?? 'discord',
|
|
22
|
+
},
|
|
23
|
+
method,
|
|
24
|
+
argTypes,
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export const listener = createComponentDecorator(ListenerComponent)
|