Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
K
koishi-decorators
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
vlssu
koishi-decorators
Commits
6c959cf8
Commit
6c959cf8
authored
Mar 13, 2022
by
nanahira
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'put-type'
parents
5fddfa16
50d2d8d6
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
197 additions
and
28 deletions
+197
-28
package-lock.json
package-lock.json
+2
-2
package.json
package.json
+1
-1
src/decorators/decorators.ts
src/decorators/decorators.ts
+10
-1
src/def/constants.ts
src/def/constants.ts
+7
-1
src/def/interfaces.ts
src/def/interfaces.ts
+7
-0
src/registry/abstract-registry.ts
src/registry/abstract-registry.ts
+3
-0
src/registry/registries/command-put.ts
src/registry/registries/command-put.ts
+84
-14
src/registry/registries/do-register.ts
src/registry/registries/do-register.ts
+9
-4
src/utility/index.ts
src/utility/index.ts
+1
-0
src/utility/native-type-mapping.ts
src/utility/native-type-mapping.ts
+21
-0
src/utility/utility.ts
src/utility/utility.ts
+9
-2
tests/register.spec.ts
tests/register.spec.ts
+43
-3
No files found.
package-lock.json
View file @
6c959cf8
{
"name"
:
"koishi-decorators"
,
"version"
:
"1.2.
8
"
,
"version"
:
"1.2.
9
"
,
"lockfileVersion"
:
2
,
"requires"
:
true
,
"packages"
:
{
""
:
{
"name"
:
"koishi-decorators"
,
"version"
:
"1.2.
8
"
,
"version"
:
"1.2.
9
"
,
"license"
:
"MIT"
,
"dependencies"
:
{
"@types/koa"
:
"^2.13.4"
,
...
...
package.json
View file @
6c959cf8
{
"name"
:
"koishi-decorators"
,
"description"
:
"Decorator defs for Koishi, especially for thirdeye and nestjs."
,
"version"
:
"1.2.
8
"
,
"version"
:
"1.2.
9
"
,
"main"
:
"dist/index.js"
,
"types"
:
"dist/index.d.ts"
,
"scripts"
:
{
...
...
src/decorators/decorators.ts
View file @
6c959cf8
...
...
@@ -60,11 +60,18 @@ export function UseCommand(
const
putOptions
:
CommandPut
.
Config
<
keyof
CommandPut
.
ConfigMap
>
[]
=
Reflect
.
getMetadata
(
KoishiCommandPutDef
,
obj
.
constructor
,
key
)
||
undefined
;
// eslint-disable-next-line @typescript-eslint/ban-types
const
paramTypes
:
Function
[]
=
Reflect
.
getMetadata
(
'
design:paramtypes
'
,
obj
,
key
,
);
const
metadataDec
=
DoRegister
.
command
({
def
,
desc
,
config
,
putOptions
,
paramTypes
,
});
return
metadataDec
(
obj
,
key
,
des
);
};
...
...
@@ -177,7 +184,8 @@ export const PutArgv = (field?: keyof Argv) =>
field
?
CommandPut
.
decorate
(
'
argvField
'
,
field
)
:
CommandPut
.
decorate
(
'
argv
'
);
export
const
PutSession
=
(
field
?:
keyof
Session
)
=>
field
?
CommandPut
.
decorate
(
'
sessionField
'
,
field
)
:
PutArgv
(
'
session
'
);
export
const
PutArg
=
(
i
:
number
)
=>
CommandPut
.
decorate
(
'
arg
'
,
i
);
export
const
PutArg
=
(
index
:
number
,
decl
?:
Argv
.
Declaration
)
=>
CommandPut
.
decorate
(
'
arg
'
,
{
index
,
decl
});
export
const
PutArgs
=
()
=>
CommandPut
.
decorate
(
'
args
'
);
export
const
PutOption
=
(
name
:
string
,
...
...
@@ -213,6 +221,7 @@ export const PutTemplate = (name: string, text: string | Dict<string>) =>
name
,
text
:
adaptLocaleDict
(
text
),
});
export
const
PutObject
=
()
=>
CommandPut
.
decorate
(
'
typeClass
'
);
export
const
TopLevelAction
=
(
action
:
TopLevelActionDef
):
ClassDecorator
=>
Metadata
.
append
(
'
KoishiTopLevelAction
'
,
action
);
...
...
src/def/constants.ts
View file @
6c959cf8
// metadatas
import
{
CommandDefinitionFun
,
MappingStruct
,
OnContextFunction
,
TopLevelActionDef
,
}
from
'
./interfaces
'
;
import
{
DoRegister
}
from
'
../registry
'
;
import
{
CommandPut
,
DoRegister
}
from
'
../registry
'
;
export
const
KoishiOnContextScope
=
'
KoishiOnContextScope
'
;
export
const
KoishiDoRegister
=
'
KoishiDoRegister
'
;
...
...
@@ -19,8 +20,13 @@ export interface MetadataArrayMap {
KoishiCommandDefinition
:
CommandDefinitionFun
;
KoishiDoRegisterKeys
:
string
;
KoishiTopLevelAction
:
TopLevelActionDef
;
KoishiPutClassFieldKeys
:
string
;
}
export
interface
MetadataMap
{
KoishiDoRegister
:
DoRegister
.
Config
;
KoishiPutClassField
:
MappingStruct
<
CommandPut
.
ConfigMap
,
keyof
CommandPut
.
ConfigMap
>
;
}
src/def/interfaces.ts
View file @
6c959cf8
...
...
@@ -103,6 +103,8 @@ export interface CommandRegisterConfig<D extends string = string> {
desc
?:
string
;
config
?:
CommandConfigExtended
;
putOptions
?:
CommandPut
.
Config
[];
// eslint-disable-next-line @typescript-eslint/ban-types
paramTypes
:
Function
[];
}
export
interface
CommandConfigExtended
extends
Command
.
Config
{
...
...
@@ -157,3 +159,8 @@ export interface CommandLocaleDef extends Store {
options
?:
Dict
<
string
>
;
messages
?:
Store
;
}
export
interface
CommandArgDef
{
index
:
number
;
decl
?:
Argv
.
Declaration
;
}
src/registry/abstract-registry.ts
View file @
6c959cf8
...
...
@@ -32,6 +32,9 @@ export class MethodRegistry<
EXT
extends
any
[]
=
[],
>
extends
AbstractRegistry
<
MethodMap
<
M
,
R
,
EXT
>>
{
execute
<
K
extends
keyof
M
>
(
info
:
MappingStruct
<
M
,
K
>
,
...
ext
:
EXT
)
{
if
(
!
info
)
{
return
;
}
const
fun
=
this
.
get
(
info
.
type
);
if
(
!
fun
)
{
return
;
...
...
src/registry/registries/command-put.ts
View file @
6c959cf8
import
{
Argv
,
Command
,
Context
,
FieldCollector
,
Session
,
User
}
from
'
koishi
'
;
import
{
CommandArgDef
,
CommandOptionConfig
,
GenerateMappingStruct
,
KoishiCommandPutDef
,
...
...
@@ -7,13 +8,19 @@ import {
TemplateConfig
,
}
from
'
../../def
'
;
import
{
MethodRegistry
}
from
'
../abstract-registry
'
;
import
{
applyOptionToCommand
,
registerTemplate
}
from
'
../../utility
'
;
import
{
applyNativeTypeToArg
,
applyOptionToCommand
,
registerTemplate
,
}
from
'
../../utility
'
;
import
{
Metadata
}
from
'
../../meta/metadata.decorators
'
;
import
{
reflector
}
from
'
../../meta/meta-fetch
'
;
// eslint-disable-next-line @typescript-eslint/no-namespace
export
namespace
CommandPut
{
export
interface
ConfigMap
{
args
:
void
;
arg
:
number
;
arg
:
CommandArgDef
;
argv
:
void
;
argvField
:
keyof
Argv
;
option
:
CommandOptionConfig
;
...
...
@@ -24,6 +31,7 @@ export namespace CommandPut {
sessionField
:
keyof
Session
;
renderer
:
string
|
undefined
;
template
:
TemplateConfig
;
typeClass
:
void
;
}
export
type
Config
<
K
extends
keyof
ConfigMap
=
keyof
ConfigMap
>
=
...
...
@@ -32,13 +40,26 @@ export namespace CommandPut {
export
const
preRegistry
=
new
MethodRegistry
<
ConfigMap
,
void
,
[
Command
,
Context
]
// eslint-disable-next-line @typescript-eslint/ban-types
[
Command
,
Context
,
Function
]
>
();
preRegistry
.
extend
(
'
option
'
,
(
data
,
cmd
,
ctx
)
=>
applyOptionToCommand
(
ctx
,
cmd
,
data
),
preRegistry
.
extend
(
'
option
'
,
(
data
,
cmd
,
ctx
,
nativeType
)
=>
applyOptionToCommand
(
ctx
,
cmd
,
data
,
nativeType
),
);
preRegistry
.
extend
(
'
arg
'
,
(
data
,
cmd
,
ctx
,
nativeType
)
=>
{
let
arg
=
cmd
.
_arguments
[
data
.
index
];
if
(
!
arg
)
{
arg
=
{};
cmd
.
_arguments
[
data
.
index
]
=
arg
;
}
applyNativeTypeToArg
(
arg
,
nativeType
);
if
(
data
.
decl
)
{
Object
.
assign
(
arg
,
data
.
decl
);
}
});
preRegistry
.
extend
(
'
user
'
,
(
data
,
cmd
)
=>
{
if
(
data
)
{
cmd
.
userFields
(
data
);
...
...
@@ -61,10 +82,29 @@ export namespace CommandPut {
registerTemplate
(
data
,
ctx
,
cmd
),
);
export
const
registry
=
new
MethodRegistry
<
ConfigMap
,
any
,
[
Argv
,
any
[]]
>
();
preRegistry
.
extend
(
'
typeClass
'
,
(
data
,
cmd
,
ctx
,
nativeType
)
=>
{
const
keys
=
reflector
.
getArray
(
'
KoishiPutClassFieldKeys
'
,
nativeType
);
for
(
const
key
of
keys
)
{
const
meta
=
reflector
.
get
(
'
KoishiPutClassField
'
,
nativeType
,
key
);
if
(
!
meta
)
continue
;
const
propertyNativeType
=
Reflect
.
getMetadata
(
'
design:type
'
,
nativeType
.
prototype
,
key
,
);
preRegistry
.
execute
(
meta
,
cmd
,
ctx
,
propertyNativeType
);
}
});
export
const
registry
=
new
MethodRegistry
<
ConfigMap
,
any
,
// eslint-disable-next-line @typescript-eslint/ban-types
[
Argv
,
any
[],
Function
]
>
();
registry
.
extend
(
'
args
'
,
(
data
,
argv
,
args
)
=>
args
);
registry
.
extend
(
'
arg
'
,
(
data
,
argv
,
args
)
=>
args
[
data
]);
registry
.
extend
(
'
arg
'
,
(
data
,
argv
,
args
)
=>
args
[
data
.
index
]);
registry
.
extend
(
'
argv
'
,
(
data
,
argv
,
args
)
=>
argv
);
registry
.
extend
(
'
argvField
'
,
(
data
,
argv
,
args
)
=>
argv
[
data
]);
registry
.
extend
(
'
option
'
,
(
data
,
argv
,
args
)
=>
argv
.
options
[
data
.
name
]);
...
...
@@ -99,17 +139,47 @@ export namespace CommandPut {
(
data
,
argv
,
args
)
=>
(
params
:
object
)
=>
argv
.
session
.
text
(
`.
${
data
.
name
}
`
,
params
),
);
registry
.
extend
(
'
typeClass
'
,
(
data
,
argv
,
args
,
nativeType
:
{
new
():
any
})
=>
{
const
keys
=
reflector
.
getArray
(
'
KoishiPutClassFieldKeys
'
,
nativeType
);
const
obj
=
new
nativeType
();
for
(
const
key
of
keys
)
{
const
meta
=
reflector
.
get
(
'
KoishiPutClassField
'
,
nativeType
,
key
);
if
(
!
meta
)
continue
;
const
propertyNativeType
=
Reflect
.
getMetadata
(
'
design:type
'
,
nativeType
.
prototype
,
key
,
);
obj
[
key
]
=
registry
.
execute
(
meta
,
argv
,
args
,
propertyNativeType
);
}
return
obj
;
},
);
export
function
decorate
<
T
extends
keyof
ConfigMap
>
(
type
:
T
,
data
?:
ConfigMap
[
T
],
):
ParameterDecorator
{
return
(
obj
,
key
:
string
,
index
)
=>
{
const
objClass
=
obj
.
constructor
;
const
list
:
Config
<
T
>
[]
=
Reflect
.
getMetadata
(
KoishiCommandPutDef
,
objClass
,
key
)
||
[];
list
[
index
]
=
GenerateMappingStruct
(
type
,
data
);
Reflect
.
defineMetadata
(
KoishiCommandPutDef
,
list
,
objClass
,
key
);
):
ParameterDecorator
&
PropertyDecorator
{
return
(
obj
,
key
:
string
,
index
?:
number
)
=>
{
const
def
=
GenerateMappingStruct
(
type
,
data
);
if
(
typeof
index
===
'
number
'
)
{
// As a parameter decorator
const
objClass
=
obj
.
constructor
;
const
list
:
Config
<
T
>
[]
=
Reflect
.
getMetadata
(
KoishiCommandPutDef
,
objClass
,
key
)
||
[];
list
[
index
]
=
def
;
Reflect
.
defineMetadata
(
KoishiCommandPutDef
,
list
,
objClass
,
key
);
}
else
{
// As a property decorator
Metadata
.
set
(
'
KoishiPutClassField
'
,
def
,
'
KoishiPutClassFieldKeys
'
,
)(
obj
,
key
);
}
return
obj
;
};
}
}
src/registry/registries/do-register.ts
View file @
6c959cf8
...
...
@@ -133,12 +133,17 @@ export namespace DoRegister {
obj
[
key
](
argv
,
...
args
),
);
}
else
{
for
(
const
putOption
of
data
.
putOptions
)
{
CommandPut
.
preRegistry
.
execute
(
putOption
,
command
,
ctx
);
for
(
let
i
=
0
;
i
<
data
.
putOptions
.
length
;
i
++
)
{
const
putOption
=
data
.
putOptions
[
i
];
if
(
!
putOption
)
{
continue
;
}
const
nativeType
=
data
.
paramTypes
[
i
];
CommandPut
.
preRegistry
.
execute
(
putOption
,
command
,
ctx
,
nativeType
);
}
command
.
action
((
argv
:
Argv
,
...
args
:
any
[])
=>
{
const
params
=
data
.
putOptions
.
map
((
o
)
=>
CommandPut
.
registry
.
execute
(
o
,
argv
,
args
),
const
params
=
data
.
putOptions
.
map
((
o
,
i
)
=>
CommandPut
.
registry
.
execute
(
o
,
argv
,
args
,
data
.
paramTypes
[
i
]
),
);
return
obj
[
key
](...
params
);
});
...
...
src/utility/index.ts
View file @
6c959cf8
export
*
from
'
./utility
'
;
export
*
from
'
./native-type-mapping
'
;
src/utility/native-type-mapping.ts
0 → 100644
View file @
6c959cf8
import
{
Argv
}
from
'
koishi
'
;
// eslint-disable-next-line @typescript-eslint/ban-types
export
const
nativeTypeMapping
=
new
Map
<
Function
,
Argv
.
Type
>
();
nativeTypeMapping
.
set
(
String
,
'
string
'
);
nativeTypeMapping
.
set
(
Number
,
'
number
'
);
nativeTypeMapping
.
set
(
Boolean
,
'
boolean
'
);
nativeTypeMapping
.
set
(
Date
,
'
date
'
);
export
function
applyNativeTypeToArg
(
arg
:
Argv
.
Declaration
,
// eslint-disable-next-line @typescript-eslint/ban-types
nativeType
:
Function
,
)
{
if
(
arg
.
type
||
!
nativeType
)
{
return
;
}
if
(
nativeTypeMapping
.
has
(
nativeType
))
{
arg
.
type
=
nativeTypeMapping
.
get
(
nativeType
);
}
}
src/utility/utility.ts
View file @
6c959cf8
...
...
@@ -5,6 +5,7 @@ import {
OnContextFunction
,
TemplateConfig
,
}
from
'
../def
'
;
import
{
applyNativeTypeToArg
}
from
'
./native-type-mapping
'
;
export
function
applySelector
(
ctx
:
Context
,
...
...
@@ -59,8 +60,11 @@ export function applyOptionToCommand(
ctx
:
Context
,
cmd
:
Command
,
def
:
CommandOptionConfig
,
// eslint-disable-next-line @typescript-eslint/ban-types
nativeType
?:
Function
,
)
{
const
{
name
,
desc
,
config
}
=
def
;
const
{
name
,
config
}
=
def
;
const
{
desc
}
=
def
;
if
(
config
?.
description
)
{
const
desc
=
adaptLocaleDict
(
config
.
description
);
for
(
const
[
locale
,
text
]
of
Object
.
entries
(
desc
))
{
...
...
@@ -69,5 +73,8 @@ export function applyOptionToCommand(
}
const
clonedConfig
=
{
...(
config
||
{})
};
delete
clonedConfig
.
description
;
return
cmd
.
option
(
name
,
desc
,
clonedConfig
);
cmd
=
cmd
.
option
(
name
,
desc
,
clonedConfig
);
const
option
=
cmd
.
_options
[
name
];
applyNativeTypeToArg
(
option
,
nativeType
);
return
cmd
;
}
tests/register.spec.ts
View file @
6c959cf8
import
{
CommandUsage
,
PutArg
,
PutObject
,
PutOption
,
UseCommand
,
UseEvent
,
UseMiddleware
,
}
from
'
../src/decorators
/decorators
'
;
}
from
'
../src/decorators
'
;
import
{
App
,
Command
,
Next
,
Session
}
from
'
koishi
'
;
import
{
Registrar
}
from
'
../src/register
'
;
import
{
EventNameAndPrepend
}
from
'
../src/def
'
;
class
SkirtArg
{
@
PutArg
(
0
)
count
:
number
;
@
PutOption
(
'
color
'
,
'
-c <color>
'
)
color
:
string
;
}
class
MyClass
{
@
UseMiddleware
()
async
onPing
(
session
:
Session
,
next
:
Next
)
{
...
...
@@ -27,9 +37,19 @@ class MyClass {
@
UseCommand
(
'
echo
'
,
'
hi
'
)
@
CommandUsage
(
'
foo
'
)
async
onEcho
(@
PutOption
(
'
content
'
,
'
-c <content
:string
>
'
)
content
:
string
)
{
async
onEcho
(@
PutOption
(
'
content
'
,
'
-c <content>
'
)
content
:
string
)
{
return
`bot:
${
content
}
`
;
}
@
UseCommand
(
'
count
'
)
async
onCount
(@
PutArg
(
0
)
count
:
number
)
{
return
`I have
${
count
}
dresses.`
;
}
@
UseCommand
(
'
skirt
'
)
async
onSkirt
(@
PutObject
()
arg
:
SkirtArg
)
{
return
`I have
${
arg
.
count
}
${
arg
.
color
}
skirts.`
;
}
}
const
registrar
=
new
Registrar
(
new
MyClass
());
...
...
@@ -54,14 +74,34 @@ describe('Register', () => {
expect
((
result
.
data
as
EventNameAndPrepend
).
name
).
toBe
(
'
message
'
);
});
it
(
'
should register command
'
,
()
=>
{
it
(
'
should register command
and infer option type
'
,
()
=>
{
const
result
=
registrar
.
register
(
app
,
'
onEcho
'
);
expect
(
result
.
type
).
toBe
(
'
command
'
);
const
command
:
Command
=
result
.
result
;
expect
(
command
.
_usage
).
toBe
(
'
foo
'
);
expect
(
command
.
_options
.
content
.
name
).
toBe
(
'
content
'
);
expect
(
command
.
_options
.
content
.
type
).
toBe
(
'
string
'
);
expect
(
command
.
execute
({
options
:
{
content
:
'
hello
'
}
})).
resolves
.
toBe
(
'
bot: hello
'
,
);
});
it
(
'
should infer argument type
'
,
()
=>
{
const
result
=
registrar
.
register
(
app
,
'
onCount
'
);
expect
(
result
.
type
).
toBe
(
'
command
'
);
const
command
:
Command
=
result
.
result
;
expect
(
command
.
_arguments
[
0
].
type
).
toBe
(
'
number
'
);
expect
(
command
.
execute
({
args
:
[
'
4
'
]
})).
resolves
.
toBe
(
'
I have 4 dresses.
'
);
});
it
(
'
should work on class type
'
,
()
=>
{
const
result
=
registrar
.
register
(
app
,
'
onSkirt
'
);
expect
(
result
.
type
).
toBe
(
'
command
'
);
const
command
:
Command
=
result
.
result
;
expect
(
command
.
_arguments
[
0
].
type
).
toBe
(
'
number
'
);
expect
(
command
.
_options
.
color
.
type
).
toBe
(
'
string
'
);
expect
(
command
.
execute
({
args
:
[
'
4
'
],
options
:
{
color
:
'
red
'
}
}),
).
resolves
.
toBe
(
'
I have 4 red skirts.
'
);
});
});
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