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
e6abd888
Commit
e6abd888
authored
Jun 03, 2022
by
nanahira
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
support fork plugin
parent
f0b6284e
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
184 additions
and
22 deletions
+184
-22
src/base-plugin.ts
src/base-plugin.ts
+46
-1
src/decorators.ts
src/decorators.ts
+5
-0
src/def/constants.ts
src/def/constants.ts
+2
-0
src/def/interfaces.ts
src/def/interfaces.ts
+6
-1
src/plugin-operators/multi-plugin.ts
src/plugin-operators/multi-plugin.ts
+1
-0
src/register.ts
src/register.ts
+45
-19
tests/fork.spec.ts
tests/fork.spec.ts
+78
-0
tests/inject-using.spec.ts
tests/inject-using.spec.ts
+1
-1
No files found.
src/base-plugin.ts
View file @
e6abd888
import
{
Context
}
from
'
koishi
'
;
import
{
ClassType
}
from
'
schemastery-gen
'
;
import
{
InjectConfig
,
PluginSchema
}
from
'
./decorators
'
;
import
{
Fork
,
InjectConfig
,
PluginSchema
}
from
'
./decorators
'
;
import
{
ExactClassPluginConfig
,
PluginClass
,
TypeFromClass
}
from
'
./def
'
;
import
{
LifecycleEvents
}
from
'
./register
'
;
export
type
PartialDeep
<
T
>
=
T
extends
|
string
...
...
@@ -45,3 +47,46 @@ export function StarterPlugin<C>(config: ClassType<C>) {
PluginSchema
(
config
)(
plugin
);
return
plugin
;
}
export
function
ParentPlugin
<
PC
extends
PluginClass
>
(
child
:
PC
)
{
const
plugin
=
class
ParentPluginBase
extends
StarterPlugin
<
ExactClassPluginConfig
<
PC
>>
(
child
[
'
Config
'
])
implements
LifecycleEvents
{
onFork
(
instance
:
TypeFromClass
<
PC
>
):
void
|
Promise
<
void
>
{}
onForkDisconnect
(
instance
:
TypeFromClass
<
PC
>
):
void
|
Promise
<
void
>
{}
};
Fork
(
child
)(
plugin
);
return
plugin
;
}
export
function
ParentPluginSet
<
PC
extends
PluginClass
>
(
child
:
PC
)
{
return
class
ParentPluginSet
extends
ParentPlugin
(
child
)
{
instances
=
new
Set
<
TypeFromClass
<
PC
>>
();
onFork
(
instance
:
TypeFromClass
<
PC
>
)
{
this
.
instances
.
add
(
instance
);
}
onForkDisconnect
(
instance
:
TypeFromClass
<
PC
>
)
{
this
.
instances
.
delete
(
instance
);
}
};
}
export
function
ParentPluginMap
<
PC
extends
PluginClass
,
R
>
(
child
:
PC
,
classifyFunction
:
(
instance
:
TypeFromClass
<
PC
>
)
=>
R
,
)
{
return
class
ParentPluginMapBase
extends
ParentPlugin
(
child
)
{
instances
=
new
Map
<
R
,
TypeFromClass
<
PC
>>
();
onFork
(
instance
:
TypeFromClass
<
PC
>
)
{
this
.
instances
.
set
(
classifyFunction
(
instance
),
instance
);
}
onForkDisconnect
(
instance
:
TypeFromClass
<
PC
>
)
{
this
.
instances
.
delete
(
classifyFunction
(
instance
));
}
};
}
src/decorators.ts
View file @
e6abd888
...
...
@@ -10,6 +10,7 @@ import {
KoishiServiceProvideSym
,
KoishiSystemInjectSym
,
KoishiSystemInjectSymKeys
,
PluginClass
,
ProvideOptions
,
ServiceName
,
SystemInjectFun
,
...
...
@@ -98,6 +99,7 @@ export const InjectApp = () => InjectSystem((obj) => obj.__ctx.app);
export
const
InjectConfig
=
()
=>
InjectSystem
((
obj
)
=>
obj
.
__config
);
export
const
InjectLogger
=
(
name
?:
string
)
=>
InjectSystem
((
obj
)
=>
obj
.
__ctx
.
logger
(
name
||
obj
.
constructor
.
name
));
export
const
InjectParent
=
()
=>
InjectSystem
((
obj
)
=>
obj
.
__ctx
.
__parent
);
export
const
Caller
=
()
=>
InjectSystem
((
obj
)
=>
{
const
targetCtx
:
Context
=
obj
[
Context
.
current
]
||
obj
.
__ctx
;
...
...
@@ -151,3 +153,6 @@ export const MixinModel = <K extends Keys<Tables>>(
const
registrar
=
new
ModelRegistrar
(
ctx
.
model
);
registrar
.
mixinModel
(
tableName
,
classDict
);
});
export
const
Fork
=
(
forkPlugin
:
PluginClass
)
=>
Metadata
.
set
(
'
KoishiFork
'
,
forkPlugin
);
src/def/constants.ts
View file @
e6abd888
...
...
@@ -2,6 +2,7 @@
import
{
Context
,
Schema
}
from
'
koishi
'
;
import
{
ControlType
,
PluginClass
,
ProvideDefinition
,
ServiceName
,
SystemInjectFun
,
...
...
@@ -32,6 +33,7 @@ export interface MetadataMap {
KoishiSystemInjectSym
:
SystemInjectFun
;
KoishiPredefineSchema
:
Schema
|
ClassType
<
any
>
;
KoishiPredefineName
:
string
;
KoishiFork
:
PluginClass
;
}
export
const
ThirdEyeSym
=
Symbol
(
'
ThirdEyeSym
'
);
src/def/interfaces.ts
View file @
e6abd888
...
...
@@ -7,7 +7,7 @@ export * from 'koishi-decorators/dist/src/def/interfaces';
export
type
SystemInjectFun
=
<
T
=
any
>
(
obj
:
PluginMeta
<
T
>
)
=>
any
;
export
type
ServiceName
=
keyof
Context
;
export
type
ServiceName
=
keyof
Context
|
string
;
export
interface
ProvideOptions
extends
Context
.
ServiceOptions
{
immediate
?:
boolean
;
...
...
@@ -42,6 +42,9 @@ export type ClassPluginConfig<P extends PluginClass> = P extends PluginClass<
?
C
:
never
;
export
type
ExactClassPluginConfig
<
P
extends
PluginClass
>
=
P
extends
PluginClass
<
any
,
{
config
:
infer
IC
}
>
?
IC
:
ClassPluginConfig
<
P
>
;
export
type
MapPluginToConfig
<
M
extends
Dict
<
PluginClass
>>
=
{
[
K
in
keyof
M
]:
ClassPluginConfig
<
M
[
K
]
>
;
};
...
...
@@ -61,3 +64,5 @@ export interface ControlType<
type
:
T
;
condition
:
Condition
<
ControlTypeMap
[
T
],
any
,
[
Record
<
string
,
any
>
]
>
;
}
export
type
Prop
<
T
>
=
T
;
src/plugin-operators/multi-plugin.ts
View file @
e6abd888
...
...
@@ -47,6 +47,7 @@ export class MultiInstancePluginFramework<InnerPlugin extends PluginClass>
delete
this
.
instances
;
}
// eslint-disable-next-line @typescript-eslint/no-empty-function
onApply
()
{}
}
...
...
src/register.ts
View file @
e6abd888
...
...
@@ -30,7 +30,7 @@ export interface PluginMeta<T = any> {
__config
:
T
;
__registrar
:
Registrar
;
__pluginOptions
:
KoishiPluginRegistrationOptions
<
T
>
;
__
forkInstances
:
any
[];
__
promisesToWaitFor
:
Promise
<
void
>
[];
}
export
interface
OnApply
{
...
...
@@ -49,6 +49,14 @@ export interface LifecycleEvents {
onApply
?():
void
;
onConnect
?():
void
|
Promise
<
void
>
;
onDisconnect
?():
void
|
Promise
<
void
>
;
onFork
?(
instance
:
any
):
void
|
Promise
<
void
>
;
onForkDisconnect
?(
instance
:
any
):
void
|
Promise
<
void
>
;
}
declare
module
'
koishi
'
{
interface
Context
{
__parent
?:
any
;
}
}
export
function
DefinePlugin
<
T
>
(
...
...
@@ -78,24 +86,25 @@ export function DefinePlugin<T>(
}
const
newClass
=
class
extends
originalClass
implements
PluginMeta
{
static
get
Config
()
{
const
schemaType
=
reflector
.
get
(
'
KoishiPredefineSchema
'
,
newClass
)
||
reflector
.
get
(
'
KoishiPredefineSchema
'
,
originalClass
);
const
schemaType
=
reflector
.
get
(
'
KoishiPredefineSchema
'
,
newClass
);
return
schemaType
?
SchemaClass
(
schemaType
)
:
undefined
;
}
static
get
using
()
{
const
list
=
reflector
.
getArray
(
KoishiAddUsingList
,
originalClass
)
.
concat
(
reflector
.
getArray
(
KoishiAddUsingList
,
newClass
));
const
list
=
reflector
.
getArray
(
KoishiAddUsingList
,
newClass
);
return
_
.
uniq
(
list
);
}
static
get
reusable
()
{
const
fork
=
reflector
.
get
(
'
KoishiFork
'
,
newClass
);
return
!!
fork
;
}
__ctx
:
Context
;
__config
:
T
;
__pluginOptions
:
KoishiPluginRegistrationOptions
<
T
>
;
__registrar
:
Registrar
;
__promisesToWaitFor
:
Promise
<
void
>
[];
__forkInstances
:
any
[];
_handleSystemInjections
()
{
const
injectKeys
=
reflector
.
getArray
(
KoishiSystemInjectSymKeys
,
this
);
...
...
@@ -228,10 +237,7 @@ export function DefinePlugin<T>(
}
_getProvidingServices
()
{
return
[
...
reflector
.
getArray
(
KoishiServiceProvideSym
,
originalClass
),
...
reflector
.
getArray
(
KoishiServiceProvideSym
,
this
),
];
return
reflector
.
getArray
(
KoishiServiceProvideSym
,
this
);
}
_handleServiceProvide
(
immediate
:
boolean
)
{
...
...
@@ -275,6 +281,29 @@ export function DefinePlugin<T>(
});
}
_initializeFork
()
{
let
fork
=
reflector
.
get
(
'
KoishiFork
'
,
this
);
if
(
!
fork
)
{
return
;
}
if
(
!
fork
[
ThirdEyeSym
])
{
fork
=
DefinePlugin
()(
fork
);
}
this
.
__ctx
.
on
(
'
fork
'
,
(
ctx
,
options
)
=>
{
ctx
.
__parent
=
this
;
const
instance
=
new
fork
(
ctx
,
options
);
ctx
.
on
(
'
dispose
'
,
()
=>
{
if
(
typeof
this
.
onForkDisconnect
===
'
function
'
)
{
this
.
onForkDisconnect
(
instance
);
}
delete
ctx
.
__parent
;
});
if
(
typeof
this
.
onFork
===
'
function
'
)
{
this
.
onFork
(
instance
);
}
});
}
_initializePluginClass
()
{
this
.
_handleSystemInjections
();
this
.
_handleServiceInjections
();
...
...
@@ -284,20 +313,19 @@ export function DefinePlugin<T>(
this
.
onApply
();
}
this
.
_handleServiceProvide
(
true
);
this
.
_initializeFork
();
this
.
_registerAfterInit
();
}
constructor
(...
args
:
any
[])
{
const
originalCtx
:
Context
=
args
[
0
];
const
config
=
args
[
1
];
const
ctx
=
new
Registrar
(
originalClass
,
newClass
).
getScopeContext
(
originalCtx
,
);
const
ctx
=
new
Registrar
(
newClass
).
getScopeContext
(
originalCtx
);
super
(
ctx
,
config
,
...
args
.
slice
(
2
));
this
.
__ctx
=
ctx
;
this
.
__config
=
config
;
this
.
__pluginOptions
=
options
;
this
.
__registrar
=
new
Registrar
(
this
,
originalClass
,
config
);
this
.
__registrar
=
new
Registrar
(
this
,
undefined
,
config
);
this
.
__promisesToWaitFor
=
[];
this
.
_initializePluginClass
();
}
...
...
@@ -306,9 +334,7 @@ export function DefinePlugin<T>(
enumerable
:
true
,
configurable
:
true
,
get
:
()
=>
reflector
.
get
(
'
KoishiPredefineName
'
,
newClass
)
||
reflector
.
get
(
'
KoishiPredefineName
'
,
originalClass
)
||
originalClass
.
name
,
reflector
.
get
(
'
KoishiPredefineName
'
,
newClass
)
||
originalClass
.
name
,
});
newClass
[
ThirdEyeSym
]
=
true
;
return
newClass
;
...
...
tests/fork.spec.ts
0 → 100644
View file @
e6abd888
import
{
RegisterSchema
,
SchemaProperty
}
from
'
schemastery-gen
'
;
import
{
DefinePlugin
}
from
'
../src/register
'
;
import
{
ParentPluginMap
,
StarterPlugin
}
from
'
../src/base-plugin
'
;
import
{
Fork
,
InjectParent
,
Provide
}
from
'
../src/decorators
'
;
import
{
UseCommand
}
from
'
koishi-decorators
'
;
import
{
App
}
from
'
koishi
'
;
import
{
Prop
}
from
'
../src/def
'
;
declare
module
'
koishi
'
{
// eslint-disable-next-line @typescript-eslint/no-namespace
namespace
Context
{
interface
Services
{
forkTest
:
MyPlugin
;
}
}
}
@
RegisterSchema
()
class
Config
{
@
SchemaProperty
()
name
:
string
;
getName
()
{
return
this
.
name
;
}
}
@
DefinePlugin
()
class
ChildPlugin
extends
StarterPlugin
(
Config
)
{
@
InjectParent
()
parent
:
Prop
<
MyPlugin
>
;
@
UseCommand
(
'
parent{{name}}
'
)
async
onParentCommand
()
{
return
this
.
parent
.
config
.
getName
();
}
@
UseCommand
(
'
child{{name}}
'
)
async
onSelfCommand
()
{
return
this
.
config
.
getName
();
}
}
@
Provide
(
'
forkTest
'
,
{
immediate
:
true
})
@
DefinePlugin
()
class
MyPlugin
extends
ParentPluginMap
(
ChildPlugin
,
(
p
)
=>
p
.
config
.
getName
())
{
isParent
=
true
;
}
describe
(
'
Fork
'
,
()
=>
{
let
app
:
App
;
beforeEach
(
async
()
=>
{
app
=
new
App
();
await
app
.
start
();
});
it
(
'
should fork a plugin
'
,
async
()
=>
{
app
.
plugin
(
MyPlugin
,
{
name
:
'
a
'
});
const
myPlugin
=
app
.
forkTest
;
expect
(
app
.
forkTest
.
config
.
getName
()).
toEqual
(
'
a
'
);
expect
(
app
.
forkTest
.
instances
.
get
(
'
a
'
).
config
.
getName
()).
toEqual
(
'
a
'
);
expect
(
app
.
forkTest
.
instances
.
get
(
'
a
'
).
parent
).
toEqual
(
myPlugin
);
expect
(
app
.
forkTest
.
instances
.
get
(
'
b
'
)).
toBeUndefined
();
app
.
plugin
(
MyPlugin
,
{
name
:
'
b
'
});
expect
(
app
.
forkTest
.
instances
.
get
(
'
b
'
).
config
.
getName
()).
toEqual
(
'
b
'
);
expect
(
myPlugin
.
instances
.
get
(
'
b
'
).
parent
).
toEqual
(
app
.
forkTest
);
const
commandChildA
=
app
.
command
(
'
childa
'
);
const
commandChildB
=
app
.
command
(
'
childb
'
);
const
commandParentA
=
app
.
command
(
'
parenta
'
);
const
commandParentB
=
app
.
command
(
'
parentb
'
);
expect
(
await
commandChildA
.
execute
({})).
toEqual
(
'
a
'
);
expect
(
await
commandChildB
.
execute
({})).
toEqual
(
'
b
'
);
expect
(
await
commandParentA
.
execute
({})).
toEqual
(
'
a
'
);
// expect(await commandParentB.execute({})).toEqual('a');
});
});
tests/inject-using.spec.ts
View file @
e6abd888
import
{
RegisterSchema
,
SchemaProperty
,
StarterPlugin
}
from
'
..
'
;
import
{
Assets
,
Bot
,
Cache
,
Context
}
from
'
koishi
'
;
import
{
Assets
,
Bot
,
Cache
}
from
'
koishi
'
;
import
{
Inject
,
PluginName
,
UsingService
}
from
'
../src/decorators
'
;
import
{
DefinePlugin
}
from
'
../src/register
'
;
import
{
ServiceName
}
from
'
../src/def
'
;
...
...
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