@pikokr/command.ts 5.0.0-dev.a0bc517 → 5.0.0-dev.d547cd1
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.d.ts +107 -34
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
- package/publish-version.js +10 -0
- package/scripts/docs.ts +8 -8
- package/src/applicationCommand/ApplicationCommand.ts +14 -18
- package/src/applicationCommand/ApplicationCommandExtension.ts +169 -0
- package/src/applicationCommand/ApplicationCommandOption.ts +9 -2
- package/src/applicationCommand/index.ts +8 -0
- package/src/core/components/BaseComponent.ts +36 -14
- package/src/core/components/ComponentArgument.ts +8 -0
- package/src/core/components/ComponentArgumentDecorator.ts +8 -0
- package/src/core/components/decoratorCreator.ts +17 -3
- package/src/core/components/index.ts +13 -3
- 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 -1
- package/src/core/hooks/moduleHook.ts +11 -3
- package/src/core/index.ts +13 -1
- package/src/core/listener/index.ts +22 -2
- package/src/core/structures/CommandClient.ts +61 -4
- package/src/core/structures/Registry.ts +29 -5
- package/src/core/structures/index.ts +8 -0
- package/src/core/symbols.ts +13 -4
- 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 +8 -8
- package/test/index.ts +40 -26
- package/tsconfig.prod.json +1 -0
- package/tsup.config.ts +8 -8
|
@@ -1,6 +1,13 @@
|
|
|
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
|
+
|
|
1
9
|
import { APIApplicationCommandOption } from 'discord.js'
|
|
2
|
-
import { createArgumentDecorator } from '../core'
|
|
3
|
-
import { ComponentArgumentDecorator } from '../core/components/ComponentArgumentDecorator'
|
|
10
|
+
import { createArgumentDecorator, ComponentArgumentDecorator } from '../core'
|
|
4
11
|
|
|
5
12
|
type Options = APIApplicationCommandOption
|
|
6
13
|
|
|
@@ -1,22 +1,28 @@
|
|
|
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
|
+
|
|
1
9
|
import { Collection } from 'discord.js'
|
|
2
10
|
import _ from 'lodash'
|
|
11
|
+
import type { ComponentHookStore } from '../hooks'
|
|
3
12
|
import { ComponentArgument } from './ComponentArgument'
|
|
4
13
|
|
|
5
|
-
export class BaseComponent<Options = unknown,
|
|
6
|
-
options: Options
|
|
14
|
+
export class BaseComponent<Options = unknown, OptionsArg = Options> {
|
|
15
|
+
options: Options
|
|
7
16
|
|
|
8
17
|
method: Function
|
|
9
18
|
|
|
19
|
+
hooks: ComponentHookStore = new Collection()
|
|
20
|
+
|
|
10
21
|
argTypes: Collection<number, ComponentArgument> = new Collection()
|
|
11
22
|
|
|
12
|
-
constructor(options:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} else if (typeof options === 'string') {
|
|
16
|
-
this.options = options as this['options']
|
|
17
|
-
} else {
|
|
18
|
-
this.options = null as unknown as this['options']
|
|
19
|
-
}
|
|
23
|
+
constructor(options: OptionsArg, method: Function, argTypes: unknown[]) {
|
|
24
|
+
this.options = this.convertOptions(options)
|
|
25
|
+
|
|
20
26
|
this.method = method
|
|
21
27
|
for (let i = 0; i < argTypes.length; i++) {
|
|
22
28
|
const element = argTypes[i]
|
|
@@ -24,11 +30,27 @@ export class BaseComponent<Options = unknown, RequiredOptions = unknown> {
|
|
|
24
30
|
}
|
|
25
31
|
}
|
|
26
32
|
|
|
27
|
-
|
|
28
|
-
return
|
|
33
|
+
convertOptions(options: OptionsArg): Options {
|
|
34
|
+
return options as unknown as Options
|
|
29
35
|
}
|
|
30
36
|
|
|
31
|
-
|
|
32
|
-
|
|
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
|
+
const result = await this.method.call(target, ...args)
|
|
52
|
+
await this.executeHook(target, 'afterCall', [result])
|
|
53
|
+
|
|
54
|
+
return result
|
|
33
55
|
}
|
|
34
56
|
}
|
|
@@ -1,3 +1,11 @@
|
|
|
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
|
+
|
|
1
9
|
import { ComponentArgumentDecorator } from './ComponentArgumentDecorator'
|
|
2
10
|
|
|
3
11
|
export class ComponentArgument {
|
|
@@ -1,4 +1,14 @@
|
|
|
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
|
+
|
|
1
9
|
import { Collection } from 'discord.js'
|
|
10
|
+
import { ComponentHookStore } from '../hooks'
|
|
11
|
+
import { getComponentHookStore } from '../hooks/componentHook'
|
|
2
12
|
import { ComponentStoreSymbol } from '../symbols'
|
|
3
13
|
import { BaseComponent } from './BaseComponent'
|
|
4
14
|
import { ComponentArgumentDecorator } from './ComponentArgumentDecorator'
|
|
@@ -24,10 +34,14 @@ export const getComponent = (target: object, key: string | symbol) => {
|
|
|
24
34
|
return store.get(key)
|
|
25
35
|
}
|
|
26
36
|
|
|
27
|
-
export const createComponentDecorator = <Options,
|
|
28
|
-
return (options:
|
|
37
|
+
export const createComponentDecorator = <Options, OptionArgs>(type: typeof BaseComponent<Options, OptionArgs>) => {
|
|
38
|
+
return (options: OptionArgs): MethodDecorator => {
|
|
29
39
|
return (target, key) => {
|
|
30
|
-
var component: BaseComponent<Options> = new type(options, Reflect.get(target, key), Reflect.getMetadata('design:paramtypes', 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
|
|
31
45
|
|
|
32
46
|
const store = getComponentStore(target)
|
|
33
47
|
|
|
@@ -1,3 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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, Options & { 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) => 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)
|
|
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
|
+
}
|
package/src/core/hooks/index.ts
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
|
-
|
|
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'
|
|
@@ -1,7 +1,15 @@
|
|
|
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
|
+
|
|
1
9
|
import { Collection } from 'discord.js'
|
|
2
10
|
import { ModuleHookStoreSymbol } from '../symbols'
|
|
3
11
|
|
|
4
|
-
type ModuleHookStore = Collection<string
|
|
12
|
+
type ModuleHookStore = Collection<string, Function[]>
|
|
5
13
|
|
|
6
14
|
export const getModuleHookStore = (target: object) => {
|
|
7
15
|
let result: ModuleHookStore | null = Reflect.getMetadata(ModuleHookStoreSymbol, target)
|
|
@@ -19,11 +27,11 @@ export const moduleHook = (name: string): MethodDecorator => {
|
|
|
19
27
|
return (target, key) => {
|
|
20
28
|
const store = getModuleHookStore(target)
|
|
21
29
|
|
|
22
|
-
let v = store.get(
|
|
30
|
+
let v = store.get(name)
|
|
23
31
|
|
|
24
32
|
if (!v) {
|
|
25
33
|
v = []
|
|
26
|
-
store.set(
|
|
34
|
+
store.set(name, v)
|
|
27
35
|
}
|
|
28
36
|
|
|
29
37
|
v.push(Reflect.get(target, key))
|
package/src/core/index.ts
CHANGED
|
@@ -1,3 +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
|
+
|
|
1
9
|
export * from './components'
|
|
2
|
-
export * from './structures'
|
|
3
10
|
export * from './hooks'
|
|
11
|
+
export * from './converter'
|
|
12
|
+
export * from './utils'
|
|
13
|
+
export * from './listener'
|
|
14
|
+
export * from './structures'
|
|
15
|
+
export * from './extensions'
|
|
@@ -1,9 +1,29 @@
|
|
|
1
|
-
|
|
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'
|
|
2
11
|
|
|
3
|
-
export class ListenerComponent extends BaseComponent<{ emitter: string }, { event: string }> {
|
|
12
|
+
export class ListenerComponent extends BaseComponent<{ emitter: string; event: string }, { emitter?: string; event: string }> {
|
|
4
13
|
defaultOptions() {
|
|
5
14
|
return { emitter: 'discord' }
|
|
6
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
|
+
}
|
|
7
27
|
}
|
|
8
28
|
|
|
9
29
|
export const listener = createComponentDecorator(ListenerComponent)
|
|
@@ -1,14 +1,71 @@
|
|
|
1
|
-
|
|
1
|
+
/*
|
|
2
|
+
* File: CommandClient.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 { Client, Snowflake, Team, User } from 'discord.js'
|
|
2
11
|
import EventEmitter from 'events'
|
|
12
|
+
import { Logger } from 'tslog'
|
|
13
|
+
import { ApplicationCommandExtension, ApplicationCommandExtensionConfig } from '../../applicationCommand/ApplicationCommandExtension'
|
|
14
|
+
import { CommandClientSymbol } from '../symbols'
|
|
3
15
|
import { Registry } from './Registry'
|
|
4
|
-
|
|
5
16
|
export class CommandClient extends EventEmitter {
|
|
6
|
-
|
|
17
|
+
ctsLogger: Logger
|
|
18
|
+
registry: Registry
|
|
19
|
+
|
|
20
|
+
owners: Set<Snowflake> = new Set()
|
|
7
21
|
|
|
8
|
-
constructor(public discord: Client) {
|
|
22
|
+
constructor(public discord: Client, public logger: Logger = new Logger({ dateTimeTimezone: Intl.DateTimeFormat().resolvedOptions().timeZone })) {
|
|
9
23
|
super()
|
|
10
24
|
|
|
25
|
+
this.ctsLogger = logger.getChildLogger({ prefix: [chalk.blue('[command.ts]')], displayFilePath: 'hidden', displayFunctionName: false })
|
|
26
|
+
|
|
27
|
+
this.registry = new Registry(this.ctsLogger, this)
|
|
28
|
+
|
|
11
29
|
this.registry.registerEventEmitter('cts', this)
|
|
12
30
|
this.registry.registerEventEmitter('discord', this.discord)
|
|
13
31
|
}
|
|
32
|
+
|
|
33
|
+
async fetchOwners() {
|
|
34
|
+
if (!this.discord.application) throw new Error('The client is not logged in.')
|
|
35
|
+
|
|
36
|
+
this.ctsLogger.info('Fetching owners...')
|
|
37
|
+
|
|
38
|
+
await this.discord.application.fetch()
|
|
39
|
+
|
|
40
|
+
const owner = this.discord.application.owner
|
|
41
|
+
|
|
42
|
+
if (!owner) throw new Error('Cannot find application owner')
|
|
43
|
+
|
|
44
|
+
const owners: string[] = []
|
|
45
|
+
|
|
46
|
+
if (owner instanceof User) {
|
|
47
|
+
this.owners.add(owner.id)
|
|
48
|
+
owners.push(owner.tag)
|
|
49
|
+
} else if (owner instanceof Team) {
|
|
50
|
+
for (const [id, member] of owner.members) {
|
|
51
|
+
this.owners.add(id)
|
|
52
|
+
owners.push(member.user.tag)
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
this.ctsLogger.info(`Fetched ${chalk.green(owners.length)} owners(${owners.map((x) => chalk.blue(x)).join(', ')})`)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async enableApplicationCommandsExtension(config: ApplicationCommandExtensionConfig) {
|
|
60
|
+
await this.registry.registerModule(new ApplicationCommandExtension(config))
|
|
61
|
+
this.ctsLogger.info('Application command extension enabled.')
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
getApplicationCommandsExtension() {
|
|
65
|
+
return this.registry.extensions.find((x) => x.constructor === ApplicationCommandExtension) as ApplicationCommandExtension | undefined
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
static getFromModule(ext: object): CommandClient {
|
|
69
|
+
return Reflect.getMetadata(CommandClientSymbol, ext)
|
|
70
|
+
}
|
|
14
71
|
}
|
|
@@ -1,17 +1,37 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: Registry.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'
|
|
1
10
|
import { Collection } from 'discord.js'
|
|
2
11
|
import EventEmitter from 'events'
|
|
3
12
|
import _ from 'lodash'
|
|
4
|
-
import {
|
|
13
|
+
import { Logger } from 'tslog'
|
|
14
|
+
import { getComponentStore } from '../components'
|
|
15
|
+
import type { BaseComponent } from '../components'
|
|
5
16
|
import { getModuleHookStore } from '../hooks'
|
|
6
17
|
import { ListenerComponent } from '../listener'
|
|
7
|
-
import {
|
|
18
|
+
import { CommandClientSymbol } from '../symbols'
|
|
19
|
+
import { CommandClient } from './CommandClient'
|
|
8
20
|
|
|
9
21
|
export class Registry {
|
|
10
22
|
extensions: object[] = []
|
|
11
23
|
|
|
12
24
|
emitters: Collection<string, EventEmitter> = new Collection()
|
|
13
25
|
|
|
14
|
-
|
|
26
|
+
logger: Logger
|
|
27
|
+
|
|
28
|
+
constructor(logger: Logger, public client: CommandClient) {
|
|
29
|
+
this.logger = logger.getChildLogger({
|
|
30
|
+
prefix: [chalk.green('[Registry]')],
|
|
31
|
+
})
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
getComponentsWithTypeGlobal<T extends typeof BaseComponent<Config>, Config>(type: T): InstanceType<T>[] {
|
|
15
35
|
const result: InstanceType<T>[] = []
|
|
16
36
|
|
|
17
37
|
for (const ext of this.extensions) {
|
|
@@ -21,7 +41,7 @@ export class Registry {
|
|
|
21
41
|
return result
|
|
22
42
|
}
|
|
23
43
|
|
|
24
|
-
getComponentsWithType<T extends typeof BaseComponent<Config
|
|
44
|
+
getComponentsWithType<T extends typeof BaseComponent<Config>, Config>(ext: object, type: T): InstanceType<T>[] {
|
|
25
45
|
const componentStore = getComponentStore(ext)
|
|
26
46
|
|
|
27
47
|
return Array.from(componentStore.filter((x) => (x.constructor as unknown) === type).values() as Iterable<InstanceType<T>>)
|
|
@@ -57,15 +77,19 @@ export class Registry {
|
|
|
57
77
|
}
|
|
58
78
|
|
|
59
79
|
async registerModule(ext: object) {
|
|
80
|
+
Reflect.defineMetadata(CommandClientSymbol, this.client, ext)
|
|
81
|
+
|
|
60
82
|
this.registerEventListeners(ext)
|
|
61
83
|
await this.runModuleHook(ext, 'load')
|
|
62
84
|
this.extensions.push(ext)
|
|
85
|
+
this.logger.info(`Module registered: ${chalk.green(ext.constructor.name)}`)
|
|
63
86
|
}
|
|
64
87
|
|
|
65
88
|
async unregisterModule(ext: object) {
|
|
66
89
|
this.unregisterEventListeners(ext)
|
|
67
90
|
await this.runModuleHook(ext, 'unload')
|
|
68
91
|
_.remove(this.extensions, (x) => x === ext)
|
|
92
|
+
this.logger.info(`Module unregistered: ${chalk.green(ext.constructor.name)}`)
|
|
69
93
|
}
|
|
70
94
|
|
|
71
95
|
runModuleHook(ext: object, hookName: string, ...args: unknown[]) {
|
|
@@ -75,7 +99,7 @@ export class Registry {
|
|
|
75
99
|
|
|
76
100
|
if (functions) {
|
|
77
101
|
for (const fn of functions) {
|
|
78
|
-
fn.
|
|
102
|
+
fn.call(ext, ...args)
|
|
79
103
|
}
|
|
80
104
|
}
|
|
81
105
|
}
|
package/src/core/symbols.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/*
|
|
2
|
+
* File: symbols.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 const ComponentStoreSymbol = Symbol()
|
|
10
|
+
export const ComponentArgStoreSymbol = Symbol()
|
|
11
|
+
export const ModuleHookStoreSymbol = Symbol()
|
|
12
|
+
export const CommandClientSymbol = Symbol()
|
|
13
|
+
export const ComponentHookSymbol = Symbol()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* File: checks.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 { BaseInteraction, Interaction, Message } from 'discord.js'
|
|
10
|
+
import { createComponentHook } from '../hooks'
|
|
11
|
+
import { ComponentHookFn } from '../hooks/componentHook'
|
|
12
|
+
import { CommandClient } from '../structures'
|
|
13
|
+
import { OwnerOnlyError } from './errors'
|
|
14
|
+
|
|
15
|
+
export const createCheckDecorator = (fn: ComponentHookFn) => createComponentHook('beforeCall', fn)
|
|
16
|
+
|
|
17
|
+
export const ownerOnly = createCheckDecorator(async (client: CommandClient, i: Interaction | Message) => {
|
|
18
|
+
let isOwner = false
|
|
19
|
+
|
|
20
|
+
if (i instanceof BaseInteraction) {
|
|
21
|
+
isOwner = client.owners.has(i.user.id)
|
|
22
|
+
} else if (i instanceof Message) {
|
|
23
|
+
isOwner = client.owners.has(i.author.id)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (!isOwner) throw new OwnerOnlyError()
|
|
27
|
+
})
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/*
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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
9
|
export * from './core'
|
|
10
10
|
export * from './applicationCommand'
|