Commit d3fb2095 authored by nanahira's avatar nanahira

infer option type

parent 5fddfa16
......@@ -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);
};
......
......@@ -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 {
......
......@@ -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;
......
......@@ -32,11 +32,12 @@ 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('user', (data, cmd) => {
......@@ -61,7 +62,12 @@ export namespace CommandPut {
registerTemplate(data, ctx, cmd),
);
export const registry = new MethodRegistry<ConfigMap, any, [Argv, any[]]>();
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]);
......
......@@ -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);
});
......
import { Command, Context, Dict } from 'koishi';
import { Argv, Command, Context, Dict } from 'koishi';
import {
CommandOptionConfig,
ContextSelector,
......@@ -55,12 +55,22 @@ export const registerTemplate = (
}
};
// eslint-disable-next-line @typescript-eslint/ban-types
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 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 +79,13 @@ 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];
if (!option.type && nativeType) {
const inferredType = nativeTypeMapping.get(nativeType);
if (inferredType) {
option.type = inferredType;
}
}
return cmd;
}
......@@ -27,7 +27,7 @@ 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}`;
}
}
......@@ -60,6 +60,7 @@ describe('Register', () => {
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',
);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment