@pikokr/command.ts 5.0.0-dev.a9cbae8 → 5.0.0-dev.c0902b8

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 (45) hide show
  1. package/.github/workflows/codeql-analysis.yml +29 -29
  2. package/.github/workflows/docs.yml +3 -3
  3. package/.vscode/settings.json +9 -9
  4. package/README.md +2 -0
  5. package/dist/index.d.ts +138 -12
  6. package/dist/index.js +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/docs/index.yml +1 -1
  9. package/package.json +17 -14
  10. package/publish-version.js +10 -0
  11. package/renovate.json +5 -0
  12. package/src/applicationCommand/ApplicationCommand.ts +15 -16
  13. package/src/applicationCommand/ApplicationCommandExtension.ts +169 -0
  14. package/src/applicationCommand/ApplicationCommandOption.ts +9 -2
  15. package/src/applicationCommand/index.ts +9 -1
  16. package/src/core/components/BaseComponent.ts +41 -11
  17. package/src/core/components/ComponentArgument.ts +8 -0
  18. package/src/core/components/ComponentArgumentDecorator.ts +9 -1
  19. package/src/core/components/decoratorCreator.ts +23 -11
  20. package/src/core/components/index.ts +13 -3
  21. package/src/core/converter/index.ts +16 -0
  22. package/src/core/extensions/CTSExtension.ts +17 -0
  23. package/src/core/extensions/Extension.ts +62 -0
  24. package/src/core/extensions/index.ts +9 -0
  25. package/src/core/hooks/componentHook.ts +40 -0
  26. package/src/core/hooks/index.ts +11 -0
  27. package/src/core/hooks/moduleHook.ts +39 -0
  28. package/src/core/index.ts +14 -0
  29. package/src/core/listener/index.ts +29 -0
  30. package/src/core/structures/CommandClient.ts +78 -0
  31. package/src/core/structures/Registry.ts +110 -0
  32. package/src/core/structures/index.ts +10 -0
  33. package/src/core/symbols.ts +13 -2
  34. package/src/core/utils/checks.ts +27 -0
  35. package/src/core/utils/errors.ts +9 -0
  36. package/src/core/utils/index.ts +10 -0
  37. package/src/index.ts +7 -6
  38. package/src/textCommand/TextCommand.ts +20 -0
  39. package/src/textCommand/TextCommandExtension.ts +128 -0
  40. package/src/textCommand/index.ts +11 -0
  41. package/src/textCommand/parameters.ts +14 -0
  42. package/test/index.ts +71 -15
  43. package/tsconfig.json +2 -2
  44. package/tsconfig.prod.json +8 -0
  45. package/tsup.config.ts +1 -0
@@ -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
+ }
@@ -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,2 +1,10 @@
1
- export { applicationCommand } from './ApplicationCommand'
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'
2
10
  export { option } from './ApplicationCommandOption'
@@ -1,20 +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> {
14
+ export class BaseComponent<Options = unknown, OptionsArg = Options> {
6
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: Partial<Options>, method: Function, argTypes: unknown[]) {
13
- if (typeof options === 'object') {
14
- this.options = _.merge(this.defaultOptions(), options)
15
- } else {
16
- this.options = options
17
- }
23
+ constructor(options: OptionsArg, method: Function, argTypes: unknown[]) {
24
+ this.options = this.convertOptions(options)
25
+
18
26
  this.method = method
19
27
  for (let i = 0; i < argTypes.length; i++) {
20
28
  const element = argTypes[i]
@@ -22,11 +30,33 @@ export class BaseComponent<Options = unknown> {
22
30
  }
23
31
  }
24
32
 
25
- defaultOptions(): Options {
26
- return ({} as unknown) as Options
33
+ convertOptions(options: OptionsArg): Options {
34
+ return options as unknown as Options
27
35
  }
28
36
 
29
- execute(target: object, args: unknown[]) {
30
- return this.method.apply(target, args)
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
31
61
  }
32
62
  }
@@ -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,3 +1,11 @@
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
+
1
9
  import _ from 'lodash'
2
10
 
3
11
  export class ComponentArgumentDecorator<Options = unknown> {
@@ -12,6 +20,6 @@ export class ComponentArgumentDecorator<Options = unknown> {
12
20
  }
13
21
 
14
22
  defaultOptions(): Options {
15
- return ({} as unknown) as Options
23
+ return {} as unknown as Options
16
24
  }
17
25
  }
@@ -1,14 +1,23 @@
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
- import { ComponentArgument } from './ComponentArgument'
5
14
  import { ComponentArgumentDecorator } from './ComponentArgumentDecorator'
6
15
 
7
- type ComponentStore = Collection<string|symbol, BaseComponent>
16
+ type ComponentStore = Collection<string | symbol, BaseComponent>
8
17
  type ComponentArgumentStore = Collection<number, ComponentArgumentDecorator>
9
18
 
10
19
  export const getComponentStore = (target: object): ComponentStore => {
11
- let result: ComponentStore|null = Reflect.getMetadata(ComponentStoreSymbol, target)
20
+ let result: ComponentStore | null = Reflect.getMetadata(ComponentStoreSymbol, target)
12
21
 
13
22
  if (!result) {
14
23
  result = new Collection()
@@ -19,22 +28,26 @@ export const getComponentStore = (target: object): ComponentStore => {
19
28
  return result
20
29
  }
21
30
 
22
- export const getComponent = (target: object, key: string|symbol) => {
31
+ export const getComponent = (target: object, key: string | symbol) => {
23
32
  const store = getComponentStore(target)
24
33
 
25
34
  return store.get(key)
26
35
  }
27
36
 
28
- export const createComponentDecorator = <Options>(type: typeof BaseComponent<Options>) => {
29
- return (options: Options): MethodDecorator => {
37
+ export const createComponentDecorator = <Options, OptionArgs>(type: typeof BaseComponent<Options, OptionArgs>) => {
38
+ return (options: OptionArgs): MethodDecorator => {
30
39
  return (target, key) => {
31
- 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
32
45
 
33
46
  const store = getComponentStore(target)
34
47
 
35
48
  const decorators = getComponentArgumentStore(target, key)
36
49
 
37
- decorators.forEach((x, i)=> {
50
+ decorators.forEach((x, i) => {
38
51
  component.argTypes.get(i)?.decorators.push(x)
39
52
  })
40
53
 
@@ -43,8 +56,8 @@ export const createComponentDecorator = <Options>(type: typeof BaseComponent<Opt
43
56
  }
44
57
  }
45
58
 
46
- export const getComponentArgumentStore = (target: object, key: string|symbol): ComponentArgumentStore => {
47
- let result: ComponentArgumentStore|null = Reflect.getMetadata(ComponentStoreSymbol, target, key)
59
+ export const getComponentArgumentStore = (target: object, key: string | symbol): ComponentArgumentStore => {
60
+ let result: ComponentArgumentStore | null = Reflect.getMetadata(ComponentStoreSymbol, target, key)
48
61
 
49
62
  if (!result) {
50
63
  result = new Collection()
@@ -66,4 +79,3 @@ export const createArgumentDecorator = <Options>(type: typeof ComponentArgumentD
66
79
  }
67
80
  }
68
81
  }
69
-
@@ -1,3 +1,13 @@
1
- import 'reflect-metadata'
2
- export * from './BaseComponent'
3
- export * from './decoratorCreator'
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,9 @@
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 './Extension'
@@ -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
+ }
package/src/core/index.ts CHANGED
@@ -1 +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'
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)