Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
K
Koishi Thirdeye
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
3rdeye
Koishi Thirdeye
Commits
a13f8e41
Commit
a13f8e41
authored
Jan 21, 2022
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add UsingService
parent
4f828a42
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
166 additions
and
317 deletions
+166
-317
README.md
README.md
+2
-288
src/decorators.ts
src/decorators.ts
+17
-2
src/def/constants.ts
src/def/constants.ts
+2
-0
src/register.ts
src/register.ts
+37
-24
tests/caller.spec.ts
tests/caller.spec.ts
+39
-0
tests/service-activate.spec.ts
tests/service-activate.spec.ts
+69
-3
No files found.
README.md
View file @
a13f8e41
...
...
@@ -8,292 +8,6 @@
npm
install
koishi-thirdeye koishi
```
## 快速入门
可以简单定义类以快速开发 Koishi 插件。
```
ts
import
{
DefinePlugin
,
SchemaProperty
,
CommandUsage
,
PutOption
,
UseCommand
,
OnApply
,
KoaContext
,
UseMiddleware
,
UseEvent
,
Get
}
from
'
koishi-thirdeye
'
;
import
{
Context
,
Session
}
from
'
koishi
'
;
export
class
MyPluginConfig
{
@
SchemaProperty
({
default
:
'
bar
'
})
foo
:
string
;
}
@
DefinePlugin
({
name
:
'
my-plugin
'
,
schema
:
MyPluginConfig
})
export
default
class
MyPlugin
implements
OnApply
{
constructor
(
private
ctx
:
Context
,
private
config
:
Partial
<
MyPluginConfig
>
)
{
}
onApply
()
{
// 该方法会在插件加载时调用,用于在上下文中注册事件等操作。
}
@
UseMiddleware
()
simpleMiddleware
(
session
:
Session
,
next
:
NextFunction
)
{
return
next
();
}
@
UseEvent
(
'
message
'
)
onMessage
(
session
:
Session
)
{
}
@
UseCommand
(
'
echo
'
,
'
命令描述
'
)
@
CommandUsage
(
'
命令说明
'
)
onEcho
(@
PutOption
(
'
content
'
,
'
-c <content:string> 命令参数
'
)
content
:
string
)
{
return
content
;
}
@
Get
(
'
/ping
'
)
onPing
(
ctx
:
KoaContext
)
{
ctx
.
body
=
'
pong
'
;
}
}
```
## 使用
使用 koishi-thirdeye 编写的插件,需要在插件类上使用
`@DefinePlugin(options: DefinePluginRegistrationOptions)`
装饰器。
您可以在参数中指定该插件的基本信息。
*
`name`
插件名称。
*
`schema`
插件的配置描述模式。可以是 Schema 描述模式,也可以是由
`schemastery-gen`
生成的 Schema 类。
koishi-thirdeye 内建了
`schemastery-gen`
的支持。只需要导入这1个包即可。另外,系统会自动进行
`@RegisterSchema`
的配置描述的注册。
最基本的插件定义方式如下:
```
ts
import
{
DefinePlugin
,
SchemaProperty
,
InjectConfig
}
from
'
koishi-thirdeye
'
;
import
{
Context
,
Session
}
from
'
koishi
'
;
export
class
MyPluginConfig
{
@
SchemaProperty
({
default
:
'
bar
'
})
foo
:
string
;
}
@
DefinePlugin
({
name
:
'
my-plugin
'
,
schema
:
MyPluginConfig
})
export
default
class
MyPlugin
{
constructor
(
private
ctx
:
Context
,
private
config
:
Partial
<
MyPluginConfig
>
)
{
}
@
InjectConfig
()
private
config
:
Config
;
}
```
### 插件基类
为了简化不必要的代码,在您的类没有其他继承的情况下,可以继承于
`BasePlugin<Config>`
类,以省去不必要的构造函数等声明。
您可以使用
`this.ctx`
以及
`this.config`
进行访问上下文对象以及插件配置。因此上面的例子可以简化为下面的代码:
> `@DefinePlugin` 装饰器不可省略。
```
ts
import
{
DefinePlugin
,
SchemaProperty
,
BasePlugin
}
from
'
koishi-thirdeye
'
;
import
{
Context
,
Session
}
from
'
koishi
'
;
export
class
MyPluginConfig
{
@
SchemaProperty
({
default
:
'
bar
'
})
foo
:
string
;
}
@
DefinePlugin
({
name
:
'
my-plugin
'
,
schema
:
MyPluginConfig
})
export
default
class
MyPlugin
extends
BasePlugin
<
MyPluginConfig
>
{
}
```
## API
### 注入
您可以在类成员变量中,使用下列装饰器进行注入成员变量。
**注入的变量在构造函数中无效。**
请在
`onApply`
等生命周期钩子函数中调用。
*
`@InjectContext(select?: Selection)`
注入上下文对象。
**注入的上下文对象会受全局选择器影响。**
*
`@InjectApp()`
注入 Koishi 实例对象。
*
`@InjectLogger(name: string)`
注入 Koishi 日志记录器。
### 声明周期钩子
下列方法是一些生命周期方法。这些方法会在插件特定生命周期中调用,便于注册方法等操作。
要声明钩子,让插件类实现对应的接口,并添加对应的方法即可。
```
ts
// 在插件加载时调用
export
interface
OnApply
{
onApply
():
void
|
Promise
<
void
>
;
}
// 在 Koishi 实例启动完毕时调用
export
interface
OnConnect
{
onConnect
():
void
|
Promise
<
void
>
;
}
// 在插件卸载或 Koishi 实例关闭时调用
export
interface
OnDisconnect
{
onDisconnect
():
void
|
Promise
<
void
>
;
}
```
### 选择器
选择器装饰器可以注册在插件类顶部,也可以注册在插件方法函数。
插件类顶部定义的上下文选择器是全局的,会影响使用
`@Inject`
或
`@InjectContext`
注入的任何上下文对象,以及构造函数中传入的上下文对象。
选择器的使用请参照
[
Koishi 文档
](
https://koishi.js.org/v4/guide/plugin/context.html#%E4%BD%BF%E7%94%A8%E9%80%89%E6%8B%A9%E5%99%A8
)
。
*
`@OnUser(value)`
等价于
`ctx.user(value)`
。
*
`@OnSelf(value)`
等价于
`ctx.self(value)`
。
*
`@OnGuild(value)`
等价于
`ctx.guild(value)`
。
*
`@OnChannel(value)`
等价于
`ctx.channel(value)`
。
*
`@OnPlatform(value)`
等价于
`ctx.platform(value)`
。
*
`@OnPrivate(value)`
等价于
`ctx.private(value)`
。
*
`@OnSelection(value)`
等价于
`ctx.select(value)`
。
*
`@OnContext((ctx: Context) => Context)`
手动指定上下文选择器,用于不支持的选择器。例如,
```
ts
@
OnContext
(
ctx
=>
ctx
.
platform
(
'
onebot
'
))
```
### 注册方法
*
`@UseMiddleware(prepend?: boolean)`
注册中间件,等价于
`ctx.middleware((session, next) => { }, prepend)`
。
[
参考
](
https://koishi.js.org/v4/guide/message/message.html#%E6%B3%A8%E5%86%8C%E5%92%8C%E5%8F%96%E6%B6%88%E4%B8%AD%E9%97%B4%E4%BB%B6
)
*
`@UseEvent(name: EventName, prepend?: boolean)`
注册事件监听器。等价于
`ctx.on(name, (session) => { }, prepend)`
。
[
参考
](
https://koishi.js.org/v4/guide/plugin/lifecycle.html#%E4%BA%8B%E4%BB%B6%E7%B3%BB%E7%BB%9F
)
*
`@UsePlugin()`
使用该方法注册插件。在 Koishi 实例注册时该方法会自动被调用。该方法需要返回插件定义,可以使用
`PluginDef(plugin, options, select)`
方法生成。
[
参考
](
https://koishi.js.org/v4/guide/plugin/plugin.html#%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6
)
*
`@UseCommand(def: string, desc?: string, config?: Command.Config)`
注册指令。指令系统可以参考
[
Koishi 文档
](
https://koishi.js.org/guide/command.html
)
。指令回调参数位置和类型和 Koishi 指令一致。
*
若指定
`config.empty`
则不会注册当前函数为 action,用于没有 action 的父指令。
*
`@Get(path: string)`
`@Post(path: string)`
在 Koishi 的 Koa 路由中注册 GET/POST 路径。此外, PUT PATCH DELETE 等方法也有所支持。
### 指令描述装饰器
koishi-thirdeye 使用一组装饰器进行描述指令的行为。这些装饰器需要和
`@UseCommand(def)`
一起使用。
*
`@CommandDescription(text: string)`
指令描述。等价于
`ctx.command(def, desc)`
中的描述。
*
`@CommandUsage(text: string)`
指令介绍。等价于
`cmd.usage(text)`
。
*
`@CommandExample(text: string)`
指令示例。等价于
`cmd.example(text)`
。
*
`@CommandAlias(def: string)`
指令别名。等价于
`cmd.alias(def)`
。
*
`@CommandShortcut(def: string, config?: Command.Shortcut)`
指令快捷方式。等价于
`cmd.shortcut(def, config)`
。
*
`@CommandDef((cmd: Command) => Command)`
手动定义指令信息,用于不支持的指令类型。
### 指令参数
指令参数也使用一组装饰器对指令参数进行注入。下列装饰器应对由
`@UseCommand`
配置的类成员方法参数进行操作。
*
`@PutArgv()`
注入
`Argv`
对象。
*
`@PutSession(field?: keyof Session)`
注入
`Session`
对象,或
`Session`
对象的指定字段。
*
`@PutArg(index: number)`
注入指令的第 n 个参数。
*
`@PutOption(name: string, desc: string, config: Argv.OptionConfig = {})`
给指令添加选项并注入到该参数。等价于
`cmd.option(name, desc, config)`
。
*
`@PutUser(fields: string[])`
添加一部分字段用于观测,并将 User 对象注入到该参数。
*
`@PutChannel(fields: string[])`
添加一部分字段用于观测,并将 Channel 对象注入到该参数。
关于 Koishi 的观察者概念详见
[
Koishi 文档
](
https://koishi.js.org/v4/guide/database/observer.html#%E8%A7%82%E5%AF%9F%E8%80%85%E5%AF%B9%E8%B1%A1
)
。
*
`@PutUserName(useDatabase: boolean = true)`
注入当前用户的用户名。
*
`useDatabase`
是否尝试从数据库获取用户名。
### 上下文 Service 交互
您可以使用装饰器与 Koishi 的 Service 系统进行交互。
#### 注入上下文 Service
注入的 Service 通常来自其他 Koishi 插件。
```
ts
import
{
Inject
,
UseEvent
}
from
'
koishi-thirdeye
'
;
import
{
Cache
}
from
'
koishi
'
;
@
DefinePlugin
({
name
:
'
my-plugin
'
})
export
class
MyPlugin
{
constructor
(
private
ctx
:
Context
,
private
config
:
any
)
{
}
// 注入 Service
@
Inject
(
'
cache
'
)
private
cache2
:
Cache
;
// 成员变量名与 Service 名称一致时 name 可省略。
@
Inject
()
private
cache
:
Cache
;
// 成员类型是 Context 会自动注入 Koishi 上下文,等效于 `@InjectContext()` 。
@
Inject
()
private
anotherCtx
:
Context
;
@
UseEvent
(
'
service/cache
'
)
async
onCacheAvailable
()
{
// 建议监听 Service 事件
const
user
=
this
.
cache
.
get
(
'
user
'
,
'
111111112
'
);
}
}
```
#### 提供上下文 Service
您也可以直接使用
`@Provide`
方法进行 Koishi 的 Service 提供,供其他插件使用。
```
ts
import
{
Provide
}
from
'
koishi-thirdeye
'
;
// 需要定义 Service 类型
declare
module
'
koishi
'
{
namespace
Context
{
interface
Services
{
myService
:
MyDatabasePlugin
;
}
}
}
// `@Provide(name)` 装饰器会自动完成 `Context.service(name)` 的声明操作
@
Provide
(
'
myService
'
)
@
DefinePlugin
({
name
:
'
my-database
'
})
export
class
MyDatabasePlugin
{
// 该类会作为 Koishi 的 Service 供其他 Koishi 插件进行引用
}
```
#### 定义
*
`@Inject(name?: string, addUsing?: boolean)`
在插件类某一属性注入特定上下文 Service 。
`name`
若为空则默认为类方法名。
`addUsing`
若为
`true`
则会为插件注册的 Service 。
特别的,为了编写简便,如果成员类型也是 Context 则会注入 Koishi 上下文,等效于
`@InjectContext()`
。
*
`@Provide(name: string, options?: ProvideOptions)`
使用该插件提供 Service 。会自动完成 Koishi 的
`Context.service(name)`
声明操作。
*
`immediate`
会在插件加载阶段瞬间完成 Service 注册。
## 文档
https://koishi.js.org/guide/misc/decorator.html
src/decorators.ts
View file @
a13f8e41
...
...
@@ -13,6 +13,7 @@ import {
KoishiDoRegister
,
KoishiDoRegisterKeys
,
KoishiOnContextScope
,
KoishiPartialUsing
,
KoishiRouteDef
,
KoishiServiceInjectSym
,
KoishiServiceInjectSymKeys
,
...
...
@@ -313,7 +314,21 @@ export const InjectLogger = (name?: string) =>
);
export
const
Caller
=
()
=>
InjectSystem
((
obj
)
=>
{
const
ctx
=
obj
.
__ctx
;
const
targetCtx
:
Context
=
ctx
[
Context
.
current
]
||
ctx
;
const
targetCtx
:
Context
=
obj
[
Context
.
current
]
||
obj
.
__ctx
;
return
targetCtx
;
});
export
function
UsingService
(
...
services
:
(
keyof
Context
.
Services
)[]
):
ClassDecorator
&
MethodDecorator
{
return
(
obj
,
key
?)
=>
{
for
(
const
service
of
services
)
{
if
(
!
key
)
{
// fallback to KoishiAddUsingList
Metadata
.
appendUnique
(
KoishiAddUsingList
,
service
)(
obj
.
constructor
);
}
else
{
Metadata
.
appendUnique
(
KoishiPartialUsing
,
service
)(
obj
,
key
);
}
}
};
}
src/def/constants.ts
View file @
a13f8e41
...
...
@@ -20,6 +20,7 @@ export const KoishiServiceProvideSym = 'KoishiServiceProvideSym';
export
const
KoishiSystemInjectSym
=
'
KoishiSystemInjectSym
'
;
export
const
KoishiSystemInjectSymKeys
=
'
KoishiSystemInjectSymKeys
'
;
export
const
KoishiAddUsingList
=
'
KoishiAddUsingList
'
;
export
const
KoishiPartialUsing
=
'
KoishiPartialUsing
'
;
// metadata map
...
...
@@ -31,6 +32,7 @@ export interface MetadataArrayMap {
KoishiServiceInjectSymKeys
:
string
;
KoishiSystemInjectSymKeys
:
string
;
KoishiAddUsingList
:
keyof
Context
.
Services
;
KoishiPartialUsing
:
keyof
Context
.
Services
;
}
export
interface
MetadataMap
{
...
...
src/register.ts
View file @
a13f8e41
...
...
@@ -6,6 +6,7 @@ import {
Schema
,
User
,
WebSocketLayer
,
Plugin
,
}
from
'
koishi
'
;
import
{
CommandPutConfig
,
...
...
@@ -16,6 +17,7 @@ import {
KoishiDoRegisterKeys
,
KoishiModulePlugin
,
KoishiOnContextScope
,
KoishiPartialUsing
,
KoishiServiceInjectSym
,
KoishiServiceInjectSymKeys
,
KoishiServiceProvideSym
,
...
...
@@ -89,10 +91,8 @@ export function DefinePlugin<T = any>(
__wsLayers
:
WebSocketLayer
[];
_handleSystemInjections
()
{
// console.log('Handling system injection');
const
injectKeys
=
reflector
.
getArray
(
KoishiSystemInjectSymKeys
,
this
);
for
(
const
key
of
injectKeys
)
{
// console.log(`Processing ${key}`);
const
valueFunction
=
reflector
.
get
(
KoishiSystemInjectSym
,
this
,
key
);
Object
.
defineProperty
(
this
,
key
,
{
configurable
:
true
,
...
...
@@ -103,10 +103,8 @@ export function DefinePlugin<T = any>(
}
_handleServiceInjections
()
{
// console.log('Handling service injection');
const
injectKeys
=
reflector
.
getArray
(
KoishiServiceInjectSymKeys
,
this
);
for
(
const
key
of
injectKeys
)
{
// console.log(`Processing ${key}`);
const
name
=
reflector
.
get
(
KoishiServiceInjectSym
,
this
,
key
);
Object
.
defineProperty
(
this
,
key
,
{
enumerable
:
true
,
...
...
@@ -231,22 +229,13 @@ export function DefinePlugin<T = any>(
}
}
_registerDeclarationsFor
(
methodKey
:
keyof
C
&
string
)
{
// console.log(`Handling declaration for ${methodKey}`);
_registerDeclarationsProcess
(
methodKey
:
keyof
C
&
string
,
ctx
:
Context
)
{
const
regData
=
reflector
.
get
(
KoishiDoRegister
,
this
,
methodKey
);
if
(
!
regData
)
{
return
;
}
// console.log(`Type: ${regData.type}`);
const
baseContext
=
getContextFromFilters
(
this
.
__ctx
,
reflector
.
getArray
(
KoishiOnContextScope
,
this
,
methodKey
),
);
switch
(
regData
.
type
)
{
case
'
middleware
'
:
const
{
data
:
midPrepend
}
=
regData
as
DoRegisterConfig
<
'
middleware
'
>
;
baseContext
.
middleware
(
ctx
.
middleware
(
(
session
,
next
)
=>
this
[
methodKey
](
session
,
next
),
midPrepend
,
);
...
...
@@ -254,7 +243,7 @@ export function DefinePlugin<T = any>(
case
'
onevent
'
:
const
{
data
:
eventData
}
=
regData
as
DoRegisterConfig
<
'
onevent
'
>
;
const
eventName
=
eventData
.
name
;
baseContext
.
on
(
ctx
.
on
(
eventName
,
(...
args
:
any
[])
=>
this
[
methodKey
](...
args
),
eventData
.
prepend
,
...
...
@@ -264,18 +253,18 @@ export function DefinePlugin<T = any>(
const
{
data
:
beforeEventData
}
=
regData
as
DoRegisterConfig
<
'
beforeEvent
'
>
;
const
beforeEventName
=
beforeEventData
.
name
;
baseContext
.
before
(
ctx
.
before
(
beforeEventName
,
(...
args
:
any
[])
=>
this
[
methodKey
](...
args
),
beforeEventData
.
prepend
,
);
case
'
plugin
'
:
this
.
_applyInnerPlugin
(
baseContext
,
methodKey
);
this
.
_applyInnerPlugin
(
ctx
,
methodKey
);
break
;
case
'
command
'
:
const
{
data
:
commandData
}
=
regData
as
DoRegisterConfig
<
'
command
'
>
;
let
command
=
baseContext
.
command
(
let
command
=
ctx
.
command
(
commandData
.
def
,
commandData
.
desc
,
commandData
.
config
,
...
...
@@ -312,13 +301,13 @@ export function DefinePlugin<T = any>(
const
realPath
=
routeData
.
path
.
startsWith
(
'
/
'
)
?
routeData
.
path
:
`/
${
routeData
.
path
}
`
;
baseContext
.
router
[
routeData
.
method
](
realPath
,
(
ctx
,
next
)
=>
ctx
.
router
[
routeData
.
method
](
realPath
,
(
ctx
,
next
)
=>
this
[
methodKey
](
ctx
,
next
),
);
break
;
case
'
ws
'
:
const
{
data
:
wsPath
}
=
regData
as
DoRegisterConfig
<
'
ws
'
>
;
const
layer
=
baseContext
.
router
.
ws
(
wsPath
,
(
socket
,
req
)
=>
const
layer
=
ctx
.
router
.
ws
(
wsPath
,
(
socket
,
req
)
=>
this
[
methodKey
](
socket
,
req
),
);
this
.
__wsLayers
.
push
(
layer
);
...
...
@@ -328,19 +317,44 @@ export function DefinePlugin<T = any>(
}
}
_registerDeclarationsFor
(
methodKey
:
keyof
C
&
string
)
{
if
(
!
reflector
.
get
(
KoishiDoRegister
,
this
,
methodKey
))
{
return
;
}
const
ctx
=
getContextFromFilters
(
this
.
__ctx
,
reflector
.
getArray
(
KoishiOnContextScope
,
this
,
methodKey
),
);
const
partialUsing
=
reflector
.
getArray
(
KoishiPartialUsing
,
this
,
methodKey
,
);
if
(
partialUsing
.
length
)
{
const
name
=
`
${
options
.
name
||
originalClass
.
name
}
-
${
methodKey
}
`
;
const
innerPlugin
:
Plugin
.
Object
=
{
name
,
using
:
partialUsing
,
apply
:
(
innerCtx
)
=>
this
.
_registerDeclarationsProcess
(
methodKey
,
innerCtx
),
};
ctx
.
plugin
(
innerPlugin
);
}
else
{
this
.
_registerDeclarationsProcess
(
methodKey
,
ctx
);
}
}
_registerDeclarations
()
{
const
methodKeys
=
reflector
.
getArray
(
KoishiDoRegisterKeys
,
this
,
)
as
(
keyof
C
&
string
)[];
// console.log(methodKeys);
methodKeys
.
forEach
((
methodKey
)
=>
this
.
_registerDeclarationsFor
(
methodKey
),
);
}
_handleServiceProvide
(
immediate
:
boolean
)
{
// console.log(`Handling service provide`);
const
providingServices
=
[
...
reflector
.
getArray
(
KoishiServiceProvideSym
,
originalClass
),
...
reflector
.
getArray
(
KoishiServiceProvideSym
,
this
),
...
...
@@ -352,7 +366,6 @@ export function DefinePlugin<T = any>(
}
_registerAfterInit
()
{
// console.log(`Handling after init.`);
this
.
__ctx
.
on
(
'
ready
'
,
async
()
=>
{
if
(
typeof
this
.
onConnect
===
'
function
'
)
{
await
this
.
onConnect
();
...
...
tests/caller.spec.ts
0 → 100644
View file @
a13f8e41
import
{
DefinePlugin
}
from
'
../src/register
'
;
import
{
BasePlugin
}
from
'
../src/base-plugin
'
;
import
{
Caller
,
Provide
}
from
'
../src/decorators
'
;
import
{
App
}
from
'
koishi
'
;
declare
module
'
koishi
'
{
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace
Context
{
interface
Services
{
callerTester
:
CallerTester
;
}
}
}
@
Provide
(
'
callerTester
'
)
@
DefinePlugin
()
class
CallerTester
extends
BasePlugin
<
any
>
{
@
Caller
()
caller
:
string
;
}
describe
(
'
Caller
'
,
()
=>
{
let
app
:
App
;
beforeEach
(
async
()
=>
{
app
=
new
App
();
app
.
plugin
(
CallerTester
);
await
app
.
start
();
});
it
(
'
should put caller with correct values
'
,
async
()
=>
{
const
ctx1
=
app
.
any
();
const
ctx2
=
app
.
any
();
const
caller1
=
ctx1
.
callerTester
.
caller
;
const
caller2
=
ctx2
.
callerTester
.
caller
;
expect
(
caller1
).
toEqual
(
ctx1
);
expect
(
caller2
).
toEqual
(
ctx2
);
expect
(
app
.
callerTester
.
caller
).
toEqual
(
app
);
});
});
tests/service-activate.spec.ts
View file @
a13f8e41
import
{
App
,
Context
}
from
'
koishi
'
;
import
{
DefinePlugin
}
from
'
../src/register
'
;
import
{
Inject
,
Provide
,
UseEvent
}
from
'
../src/decorators
'
;
import
{
Inject
,
Provide
,
UseEvent
,
UsingService
}
from
'
../src/decorators
'
;
import
{
BasePlugin
}
from
'
../src/base-plugin
'
;
declare
module
'
koishi
'
{
// eslint-disable-next-line @typescript-eslint/no-namespace
...
...
@@ -10,24 +11,39 @@ declare module 'koishi' {
myEagerProvider
:
MyEagerProvider
;
myConsumer
:
MyConsumer
;
myUsingConsumer
:
MyUsingConsumer
;
myPartialConsumer
:
MyPartialConsumer
;
dummyProvider
:
any
;
}
}
interface
EventMap
{
'
pang
'
(
message
:
string
):
Promise
<
string
>
;
'
pong
'
(
message
:
string
):
Promise
<
string
>
;
}
}
@
Provide
(
'
myProvider
'
)
@
DefinePlugin
()
class
MyProvider
{
class
MyProvider
extends
BasePlugin
<
any
>
{
ping
()
{
return
'
pong
'
;
}
dispose
()
{
return
this
.
ctx
.
dispose
();
}
}
@
Provide
(
'
myEagerProvider
'
,
{
immediate
:
true
})
@
DefinePlugin
()
class
MyEagerProvider
{
class
MyEagerProvider
extends
BasePlugin
<
any
>
{
ping
()
{
return
'
pong eager
'
;
}
dispose
()
{
return
this
.
ctx
.
dispose
();
}
}
@
Provide
(
'
myConsumer
'
,
{
immediate
:
true
})
...
...
@@ -74,6 +90,32 @@ class MyUsingConsumer {
this
.
eagerPongResult
=
this
.
myEagerProvider
.
ping
();
}
}
emitResult
:
string
;
}
@
Provide
(
'
myPartialConsumer
'
,
{
immediate
:
true
})
@
DefinePlugin
()
class
MyPartialConsumer
{
@
Inject
()
dummyProvider
:
number
;
pongResult
:
string
;
@
UsingService
(
'
dummyProvider
'
)
@
UseEvent
(
'
pang
'
)
async
onPang
(
content
:
string
)
{
const
msg
=
`pang:
${
content
}
`
;
console
.
log
(
msg
);
return
msg
;
}
@
UseEvent
(
'
pong
'
)
async
onPong
(
content
:
string
)
{
const
msg
=
`pong:
${
content
}
`
;
console
.
log
(
msg
);
return
msg
;
}
}
describe
(
'
On service
'
,
()
=>
{
...
...
@@ -111,4 +153,28 @@ describe('On service', () => {
//expect(app.myUsingConsumer.eagerPongResult).toBe('pong eager');
//expect(app.myUsingConsumer.pongResult).toBe('pong');
});
/*
it('Should handle partial using deps', async () => {
Context.service('dummyProvider');
app = new App();
app.on('service', (name) => {
console.log('service', name);
});
await app.start();
app.plugin(MyPartialConsumer);
expect(app.myPartialConsumer).toBeDefined();
expect(await app.waterfall('pang', 'hello')).toEqual('hello');
expect(await app.waterfall('pong', 'hello')).toEqual('pong: hello');
app.dummyProvider = { foo: 'bar' };
expect(await app.waterfall('pang', 'hello')).toEqual('pang: hello');
expect(await app.waterfall('pong', 'hello')).toEqual('pong: hello');
app.dummyProvider = undefined;
expect(await app.waterfall('pang', 'hi')).toEqual('hi');
expect(await app.waterfall('pong', 'hi')).toEqual('pong: hi');
app.dummyProvider = { foo: 'baz' };
expect(await app.waterfall('pang', 'hi')).toEqual('pang: hi');
expect(await app.waterfall('pong', 'hi')).toEqual('pong: hi');
});
*/
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment