Commit c7a87492 authored by nanahira's avatar nanahira

bump to koishi-decorators

parent e93149f0
Pipeline #8928 passed with stages
in 1 minute and 34 seconds
This diff is collapsed.
import 'reflect-metadata';
import { App, Context, Selection } from 'koishi';
import { Metadata } from './meta/metadata.decorators';
import { import {
BeforeEventName,
CommandConfigExtended,
CommandDefinitionFun,
CommandPutConfig,
CommandPutConfigMap,
DoRegisterConfig,
EventName,
GenerateMappingStruct,
KoishiAddUsingList, KoishiAddUsingList,
KoishiCommandDefinition,
KoishiCommandPutDef,
KoishiDoRegister,
KoishiDoRegisterKeys,
KoishiOnContextScope,
KoishiPartialUsing, KoishiPartialUsing,
KoishiRouteDef,
KoishiServiceInjectSym, KoishiServiceInjectSym,
KoishiServiceInjectSymKeys, KoishiServiceInjectSymKeys,
KoishiServiceProvideSym, KoishiServiceProvideSym,
KoishiSystemInjectSym, KoishiSystemInjectSym,
KoishiSystemInjectSymKeys, KoishiSystemInjectSymKeys,
OnContextFunction,
ProvideOptions, ProvideOptions,
SystemInjectFun, SystemInjectFun,
} from './def'; } from './def';
import 'reflect-metadata';
import {
App,
Argv,
Command,
Context,
FieldCollector,
MaybeArray,
Selection,
Session,
} from 'koishi';
import { Metadata } from './meta/metadata.decorators';
// Register methods
export const DoRegister = (value: DoRegisterConfig): MethodDecorator =>
Metadata.set(KoishiDoRegister, value, KoishiDoRegisterKeys);
export const UseMiddleware = (prepend?: boolean): MethodDecorator =>
DoRegister(GenerateMappingStruct('middleware', prepend));
export const UseEvent = (name: EventName, prepend?: boolean): MethodDecorator =>
DoRegister(GenerateMappingStruct('onevent', { name, prepend }));
export const UseBeforeEvent = (
name: BeforeEventName,
prepend?: boolean,
): MethodDecorator =>
DoRegister(GenerateMappingStruct('beforeEvent', { name, prepend }));
export const UsePlugin = (): MethodDecorator =>
DoRegister(GenerateMappingStruct('plugin'));
export const UseHttpRoute = (routeDef: KoishiRouteDef): MethodDecorator =>
DoRegister(GenerateMappingStruct('route', routeDef));
export const Get = (path: string) => UseHttpRoute({ path, method: 'get' });
export const Post = (path: string) => UseHttpRoute({ path, method: 'post' });
export const Put = (path: string) => UseHttpRoute({ path, method: 'put' });
export const Delete = (path: string) =>
UseHttpRoute({ path, method: 'delete' });
export const Patch = (path: string) => UseHttpRoute({ path, method: 'patch' });
export const Options = (path: string) =>
UseHttpRoute({ path, method: 'options' });
export const Head = (path: string) => UseHttpRoute({ path, method: 'head' });
export const All = (path: string) => UseHttpRoute({ path, method: 'all' });
export const Ws = (path: MaybeArray<string | RegExp>) =>
DoRegister(GenerateMappingStruct('ws', path));
export function UseCommand<D extends string>(
def: D,
config?: CommandConfigExtended,
): MethodDecorator;
export function UseCommand<D extends string>(
def: D,
desc: string,
config?: CommandConfigExtended,
): MethodDecorator;
export function UseCommand(
def: string,
...args: [CommandConfigExtended?] | [string, CommandConfigExtended?]
): MethodDecorator {
const desc = typeof args[0] === 'string' ? (args.shift() as string) : '';
const config = args[0] as CommandConfigExtended;
return (obj, key: string, des) => {
const putOptions: CommandPutConfig<keyof CommandPutConfigMap>[] =
Reflect.getMetadata(KoishiCommandPutDef, obj.constructor, key) ||
undefined;
const metadataDec = DoRegister({
type: 'command',
data: {
def,
desc,
config,
putOptions,
},
});
return metadataDec(obj, key, des);
};
}
// Context scopes
export const OnContext = (
ctxFun: OnContextFunction,
): MethodDecorator & ClassDecorator =>
Metadata.append(KoishiOnContextScope, ctxFun);
export const OnAnywhere = () => OnContext((ctx) => ctx.any());
export const OnNowhere = () => OnContext((ctx) => ctx.never());
export const OnUser = (...values: string[]) =>
OnContext((ctx) => ctx.user(...values));
export const OnSelf = (...values: string[]) =>
OnContext((ctx) => ctx.self(...values));
export const OnGuild = (...values: string[]) =>
OnContext((ctx) => ctx.guild(...values));
export const OnChannel = (...values: string[]) =>
OnContext((ctx) => ctx.channel(...values));
export const OnPlatform = (...values: string[]) =>
OnContext((ctx) => ctx.platform(...values));
export const OnPrivate = (...values: string[]) =>
OnContext((ctx) => ctx.private(...values));
export const OnSelection = (selection: Selection) =>
OnContext((ctx) => ctx.select(selection));
// Command definition
export const CommandDef = (
def: CommandDefinitionFun,
): MethodDecorator & ClassDecorator =>
Metadata.append(KoishiCommandDefinition, def);
export const CommandUse = <T extends Command, R extends any[]>(
callback: (command: Command, ...args: R) => T,
...args: R
) => CommandDef((cmd) => callback(cmd, ...args));
export const CommandDescription = (desc: string) =>
CommandDef((cmd) => {
cmd.description = desc;
return cmd;
});
export const CommandAlias = (...names: string[]) =>
CommandDef((cmd) => cmd.alias(...names));
export const CommandShortcut = (
name: string | RegExp,
config: Command.Shortcut = {},
) => CommandDef((cmd) => cmd.shortcut(name, config));
export const CommandUsage = (text: Command.Usage) =>
CommandDef((cmd) => cmd.usage(text));
export const CommandExample = (text: string) =>
CommandDef((cmd) => cmd.example(text));
export const CommandOption = (
name: string,
desc: string,
config: Argv.OptionConfig = {},
) => CommandDef((cmd) => cmd.option(name, desc, config));
export const CommandUserFields = (fields: FieldCollector<'user'>) =>
CommandDef((cmd) => cmd.userFields(fields));
export const CommandChannelFields = (fields: FieldCollector<'channel'>) =>
CommandDef((cmd) => cmd.channelFields(fields));
export const CommandBefore = (callback: Command.Action, append = false) =>
CommandDef((cmd) => cmd.before(callback, append));
export const CommandAction = (callback: Command.Action, prepend = false) =>
CommandDef((cmd) => cmd.action(callback, prepend));
// Command put config
function PutCommandParam<T extends keyof CommandPutConfigMap>(
type: T,
data?: CommandPutConfigMap[T],
): ParameterDecorator {
return (obj, key: string, index) => {
const objClass = obj.constructor;
const list: CommandPutConfig<T>[] =
Reflect.getMetadata(KoishiCommandPutDef, objClass, key) || [];
list[index] = GenerateMappingStruct(type, data);
Reflect.defineMetadata(KoishiCommandPutDef, list, objClass, key);
};
}
export const PutArgv = (field?: keyof Argv) =>
field ? PutCommandParam('argvField', field) : PutCommandParam('argv');
export const PutSession = (field?: keyof Session) =>
field ? PutCommandParam('sessionField', field) : PutArgv('session');
export const PutArg = (i: number) => PutCommandParam('arg', i);
export const PutArgs = () => PutCommandParam('args');
export const PutOption = (
name: string,
desc: string,
config: Argv.OptionConfig = {},
) => PutCommandParam('option', { name, desc, config });
export const PutUser = (field: FieldCollector<'user'>) =>
PutCommandParam('user', field);
export const PutChannel = (field: FieldCollector<'channel'>) =>
PutCommandParam('channel', field);
export const PutUserName = (useDatabase = true) => // Export all koishi-decorator decorators
PutCommandParam('username', useDatabase);
export const PutUserId = () => PutSession('userId'); export * from 'koishi-decorators/dist/src/decorators';
export const PutGuildId = () => PutSession('guildId');
export const PutGuildName = () => PutSession('guildName');
export const PutChannelId = () => PutSession('channelId');
export const PutChannelName = () => PutSession('channelName');
export const PutSelfId = () => PutSession('selfId');
export const PutBot = () => PutSession('bot');
export const PutNext = () => PutArgv('next');
// Service // Service API
export function Inject( export function Inject(
name?: keyof Context.Services, name?: keyof Context.Services,
......
// metadatas // metadatas
import { Context } from 'koishi'; import { Context } from 'koishi';
import { import { ProvideDefinition, SystemInjectFun } from './interfaces';
CommandDefinitionFun,
DoRegisterConfig,
OnContextFunction,
ProvideDefinition,
SystemInjectFun,
} from './interfaces';
export const KoishiOnContextScope = 'KoishiOnContextScope';
export const KoishiDoRegister = 'KoishiDoRegister';
export const KoishiDoRegisterKeys = 'KoishiDoRegisterKeys';
export const KoishiCommandDefinition = 'KoishiCommandDefinition';
export const KoishiCommandPutDef = 'KoishiCommandPutDef';
export const KoishiServiceInjectSym = 'KoishiServiceInjectSym'; export const KoishiServiceInjectSym = 'KoishiServiceInjectSym';
export const KoishiServiceInjectSymKeys = 'KoishiServiceInjectSymKeys'; export const KoishiServiceInjectSymKeys = 'KoishiServiceInjectSymKeys';
...@@ -25,10 +13,7 @@ export const KoishiPartialUsing = 'KoishiPartialUsing'; ...@@ -25,10 +13,7 @@ export const KoishiPartialUsing = 'KoishiPartialUsing';
// metadata map // metadata map
export interface MetadataArrayMap { export interface MetadataArrayMap {
KoishiOnContextScope: OnContextFunction;
KoishiCommandDefinition: CommandDefinitionFun;
KoishiServiceProvideSym: ProvideDefinition; KoishiServiceProvideSym: ProvideDefinition;
KoishiDoRegisterKeys: string;
KoishiServiceInjectSymKeys: string; KoishiServiceInjectSymKeys: string;
KoishiSystemInjectSymKeys: string; KoishiSystemInjectSymKeys: string;
KoishiAddUsingList: keyof Context.Services; KoishiAddUsingList: keyof Context.Services;
...@@ -36,7 +21,6 @@ export interface MetadataArrayMap { ...@@ -36,7 +21,6 @@ export interface MetadataArrayMap {
} }
export interface MetadataMap { export interface MetadataMap {
KoishiDoRegister: DoRegisterConfig;
KoishiServiceInjectSym: keyof Context.Services; KoishiServiceInjectSym: keyof Context.Services;
KoishiSystemInjectSym: SystemInjectFun; KoishiSystemInjectSym: SystemInjectFun;
} }
import { import { Context } from 'koishi';
Argv,
Command,
Context,
EventMap,
FieldCollector,
MaybeArray,
Modules,
Plugin,
Selection,
Session,
} from 'koishi';
import { KoishiPluginRegistrationOptions, PluginClass } from '../register'; import { KoishiPluginRegistrationOptions, PluginClass } from '../register';
import type { DefaultContext, DefaultState, ParameterizedContext } from 'koa';
import type { RouterParamContext } from '@koa/router';
export interface Type<T = any> extends Function {
new (...args: any[]): T;
}
export interface ContextSelector {
select?: Selection;
useSelector?: OnContextFunction;
}
export type KoishiPluginOptions<T extends Plugin> = boolean | Plugin.Config<T>;
export interface KoishiModulePluginExact<T extends Plugin>
extends ContextSelector {
plugin: T;
options?: boolean | KoishiPluginOptions<T>;
}
export interface KoishiModulePluginName extends ContextSelector {
plugin: string;
options?: any;
}
export type KoishiModulePlugin<T extends Plugin = any> =
| KoishiModulePluginExact<T>
| KoishiModulePluginName;
export function PluginDef(
name: string,
options?: any,
select?: Selection,
): KoishiModulePluginName;
export function PluginDef<T extends Plugin>(
plugin: T,
options?: KoishiPluginOptions<T>,
select?: Selection,
): KoishiModulePluginExact<T>;
export function PluginDef<T extends Plugin>(
plugin: T,
options?: KoishiPluginOptions<T>,
select?: Selection,
): KoishiModulePlugin<T> {
return { plugin, options, select };
}
export interface CommonEventNameAndPrepend<T extends keyof any> {
name: T;
prepend?: boolean;
}
export type EventName = keyof EventMap;
export type EventNameAndPrepend = CommonEventNameAndPrepend<EventName>;
type OmitSubstring<
S extends string,
T extends string,
> = S extends `${infer L}${T}${infer R}` ? `${L}${R}` : never;
export type BeforeEventName = OmitSubstring<EventName & string, 'before-'>;
export type BeforeEventNameAndPrepend =
CommonEventNameAndPrepend<BeforeEventName>;
export type ContextFunction<T> = (ctx: Context) => T;
export type OnContextFunction = ContextFunction<Context>;
export interface DoRegisterConfigDataMap {
middleware: boolean; // prepend
onevent: EventNameAndPrepend;
beforeEvent: BeforeEventNameAndPrepend;
plugin: never;
command: CommandRegisterConfig;
route: KoishiRouteDef;
ws: MaybeArray<string | RegExp>;
}
export interface MappingStruct<
T extends Record<string | number | symbol, any>,
K extends keyof T,
> {
type: K;
data?: T[K];
}
export function GenerateMappingStruct<
T extends Record<string | number | symbol, any>,
K extends keyof T,
>(type: K, data?: T[K]): MappingStruct<T, K> {
return {
type,
data,
};
}
export type DoRegisterConfig<
K extends keyof DoRegisterConfigDataMap = keyof DoRegisterConfigDataMap,
> = MappingStruct<DoRegisterConfigDataMap, K>;
// Command stuff // Command stuff
export interface CommandRegisterConfig<D extends string = string> {
def: D;
desc?: string;
config?: CommandConfigExtended;
putOptions?: CommandPutConfig<keyof CommandPutConfigMap>[];
}
export interface CommandConfigExtended extends Command.Config {
empty?: boolean;
}
export interface CommandOptionConfig {
name: string;
desc: string;
config?: Argv.OptionConfig;
}
export interface CommandPutConfigMap {
args: never;
arg: number;
argv: never;
argvField: keyof Argv;
option: CommandOptionConfig;
user: FieldCollector<'user'>;
channel: FieldCollector<'channel'>;
username: boolean;
sessionField: keyof Session;
}
export type CommandPutConfig<
K extends keyof CommandPutConfigMap = keyof CommandPutConfigMap,
> = MappingStruct<CommandPutConfigMap, K>;
export type CommandDefinitionFun = (cmd: Command) => Command;
export type SystemInjectFun = <T = any>( export type SystemInjectFun = <T = any>(
obj: PluginClass<T>, obj: PluginClass<T>,
pluginMeta: KoishiPluginRegistrationOptions<T>, pluginMeta: KoishiPluginRegistrationOptions<T>,
...@@ -157,22 +15,3 @@ export interface ProvideOptions { ...@@ -157,22 +15,3 @@ export interface ProvideOptions {
export interface ProvideDefinition extends ProvideOptions { export interface ProvideDefinition extends ProvideOptions {
serviceName: keyof Context.Services; serviceName: keyof Context.Services;
} }
export interface KoishiRouteDef {
path: string;
method:
| 'get'
| 'post'
| 'put'
| 'delete'
| 'patch'
| 'options'
| 'head'
| 'all';
}
export type KoaContext = ParameterizedContext<
DefaultState,
DefaultContext & RouterParamContext<DefaultState, DefaultContext>,
any
>;
This diff is collapsed.
import { Context } from 'koishi';
import { ContextSelector } from '../def';
export function getStringFromNativeType(nativeType: any) {
if (!nativeType) {
return;
}
const nativeTypeString = nativeType.toString() as string;
if (!nativeTypeString) {
return;
}
if (nativeTypeString.startsWith('class')) {
return 'class';
}
if (!nativeTypeString.startsWith('function ')) {
return;
}
return nativeType.name?.toLowerCase();
}
export function applySelector(
ctx: Context,
selector: ContextSelector,
): Context {
if (!selector) {
return ctx;
}
let targetCtx = ctx;
if (selector.select) {
targetCtx = targetCtx.select(selector.select);
}
if (selector.useSelector) {
targetCtx = selector.useSelector(targetCtx) || targetCtx;
}
return targetCtx;
}
import { App } from 'koishi'; import { App } from 'koishi';
import { DefinePlugin } from '../src/register'; import { DefinePlugin } from '../src/register';
import { Get } from '../src/decorators'; import { Get } from '../src/decorators';
import { KoaContext } from '../src/def';
import request from 'supertest'; import request from 'supertest';
import { KoaContext } from 'koishi-decorators';
@DefinePlugin() @DefinePlugin()
class MyPlugin { class MyPlugin {
......
import { App } from 'koishi'; import { App } from 'koishi';
import { DefinePlugin } from '../src/register'; import { DefinePlugin } from '../src/register';
import { UsePlugin } from '../src/decorators'; import { UsePlugin } from '../src/decorators';
import { PluginDef } from '../src/def';
import PluginOnebot from '@koishijs/plugin-adapter-onebot'; import PluginOnebot from '@koishijs/plugin-adapter-onebot';
import { BasePlugin } from '../src/base-plugin'; import { BasePlugin } from '../src/base-plugin';
import { PluginDef } from 'koishi-decorators';
@DefinePlugin() @DefinePlugin()
class MyPlugin extends BasePlugin<any> { class MyPlugin extends BasePlugin<any> {
......
import { import { CommandExample, CommandUsage, UseCommand } from '../src/decorators';
CommandExample,
CommandShortcut,
CommandUsage,
UseCommand,
} from '../src/decorators';
import { BasePlugin } from '../src/base-plugin'; import { BasePlugin } from '../src/base-plugin';
import { DefinePlugin } from '../src/register'; import { DefinePlugin } from '../src/register';
import { App, Command } from 'koishi'; import { App, Command } from 'koishi';
......
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