Commit 116e50a9 authored by nanahira's avatar nanahira

typing of metadata

parent 4bc095ae
import { Injectable } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import {
MetadataArrayMap,
MetadataGenericMap,
} from '../utility/koishi.constants';
@Injectable()
export class KoishiMetadataFetcherService {
constructor(private readonly reflector: Reflector) {}
getPropertyMetadataArray<K extends keyof MetadataArrayMap, I = any>(
metadataKey: K,
instance: I,
instanceKey: keyof I,
) {
return [
...this.getMetadataArray<K>(metadataKey, instance.constructor),
...this.getMetadataArray<K>(metadataKey, instance[instanceKey]),
];
}
getMetadataArray<K extends keyof MetadataArrayMap>(
metadataKey: K,
instance: any,
) {
return (
this.reflector.get<MetadataArrayMap[K][]>(metadataKey, instance) || []
);
}
getMetadata<K extends keyof MetadataGenericMap>(
metadataKey: K,
instance: any,
) {
return this.reflector.get<MetadataGenericMap[K]>(metadataKey, instance);
}
}
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
KoishiServiceProvideSym, KoishiServiceProvideSym,
KoishiServiceWireKeys, KoishiServiceWireKeys,
KoishiServiceWireProperty, KoishiServiceWireProperty,
MetadataArrayMap,
} from './utility/koishi.constants'; } from './utility/koishi.constants';
import { import {
CommandDefinitionFun, CommandDefinitionFun,
...@@ -44,9 +45,9 @@ export const InjectContextPlatform = (...values: string[]) => ...@@ -44,9 +45,9 @@ export const InjectContextPlatform = (...values: string[]) =>
export const InjectContextUser = (...values: string[]) => export const InjectContextUser = (...values: string[]) =>
InjectContextSpecific('user', values); InjectContextSpecific('user', values);
export const SetExtraMetadata = <K = string, V = any>( export const SetExtraMetadata = <K extends keyof MetadataArrayMap>(
metadataKey: K, metadataKey: K,
metadataValue: V, metadataValue: MetadataArrayMap[K],
): CustomDecorator<K> => { ): CustomDecorator<K> => {
const decoratorFactory = (target: any, key?: any, descriptor?: any) => { const decoratorFactory = (target: any, key?: any, descriptor?: any) => {
const currentMetadata: any[] = const currentMetadata: any[] =
...@@ -124,7 +125,7 @@ export function UseCommand( ...@@ -124,7 +125,7 @@ export function UseCommand(
export const OnContext = ( export const OnContext = (
ctxFun: OnContextFunction, ctxFun: OnContextFunction,
): MethodDecorator & ClassDecorator => ): MethodDecorator & ClassDecorator =>
SetExtraMetadata<string, OnContextFunction>(KoishiOnContextScope, ctxFun); SetExtraMetadata(KoishiOnContextScope, ctxFun);
export const OnUser = (...values: string[]) => export const OnUser = (...values: string[]) =>
OnContext((ctx) => ctx.user(...values)); OnContext((ctx) => ctx.user(...values));
...@@ -150,7 +151,7 @@ export const OnSelection = (selection: Selection) => ...@@ -150,7 +151,7 @@ export const OnSelection = (selection: Selection) =>
// Command definition // Command definition
export const CommandDef = (def: CommandDefinitionFun): MethodDecorator => export const CommandDef = (def: CommandDefinitionFun): MethodDecorator =>
SetExtraMetadata<string, CommandDefinitionFun>(KoishiCommandDefinition, def); SetExtraMetadata(KoishiCommandDefinition, def);
export const CommandDescription = (desc: string) => export const CommandDescription = (desc: string) =>
CommandDef((cmd) => { CommandDef((cmd) => {
...@@ -244,7 +245,9 @@ export function WireContextService(name?: string): PropertyDecorator { ...@@ -244,7 +245,9 @@ export function WireContextService(name?: string): PropertyDecorator {
}; };
} }
export function ProvideContextService(name: string): ClassDecorator { export function ProvideContextService(
Context.service(name as keyof Context.Services); name: keyof Context.Services,
): ClassDecorator {
Context.service(name);
return SetExtraMetadata(KoishiServiceProvideSym, name); return SetExtraMetadata(KoishiServiceProvideSym, name);
} }
...@@ -17,8 +17,6 @@ import { ...@@ -17,8 +17,6 @@ import {
KOISHI_MODULE_OPTIONS, KOISHI_MODULE_OPTIONS,
} from './utility/koishi.constants'; } from './utility/koishi.constants';
import { KoishiMiddleware } from './providers/koishi.middleware'; import { KoishiMiddleware } from './providers/koishi.middleware';
import { createServer } from 'http';
import { AddressInfo } from 'net';
import { KoishiLoggerService } from './providers/koishi-logger.service'; import { KoishiLoggerService } from './providers/koishi-logger.service';
import { KoishiMetascanService } from './providers/koishi-metascan.service'; import { KoishiMetascanService } from './providers/koishi-metascan.service';
import { DiscoveryModule, INQUIRER } from '@nestjs/core'; import { DiscoveryModule, INQUIRER } from '@nestjs/core';
...@@ -28,6 +26,7 @@ import { KoishiInjectionService } from './providers/koishi-injection.service'; ...@@ -28,6 +26,7 @@ import { KoishiInjectionService } from './providers/koishi-injection.service';
import { KoishiContextService } from './providers/koishi-context.service'; import { KoishiContextService } from './providers/koishi-context.service';
import { KoishiHttpDiscoveryService } from './koishi-http-discovery/koishi-http-discovery.service'; import { KoishiHttpDiscoveryService } from './koishi-http-discovery/koishi-http-discovery.service';
import { KoishiWebsocketGateway } from './providers/koishi-websocket.gateway'; import { KoishiWebsocketGateway } from './providers/koishi-websocket.gateway';
import { KoishiMetadataFetcherService } from './koishi-metadata-fetcher/koishi-metadata-fetcher.service';
const koishiContextProvider: Provider<Context> = { const koishiContextProvider: Provider<Context> = {
provide: KOISHI_CONTEXT, provide: KOISHI_CONTEXT,
...@@ -47,6 +46,7 @@ const koishiContextProvider: Provider<Context> = { ...@@ -47,6 +46,7 @@ const koishiContextProvider: Provider<Context> = {
KoishiContextService, KoishiContextService,
KoishiInjectionService, KoishiInjectionService,
KoishiHttpDiscoveryService, KoishiHttpDiscoveryService,
KoishiMetadataFetcherService,
], ],
exports: [KoishiService, koishiContextProvider], exports: [KoishiService, koishiContextProvider],
}) })
......
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { import { MetadataScanner, ModuleRef, ModulesContainer } from '@nestjs/core';
AbstractHttpAdapter,
HttpAdapterHost,
MetadataScanner,
ModuleRef,
ModulesContainer,
Reflector,
} from '@nestjs/core';
import { Argv, Command, Context, User } from 'koishi'; import { Argv, Command, Context, User } from 'koishi';
import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper'; import { InstanceWrapper } from '@nestjs/core/injector/instance-wrapper';
import { import {
...@@ -18,26 +11,25 @@ import { ...@@ -18,26 +11,25 @@ import {
KoishiServiceWireProperty, KoishiServiceWireProperty,
} from '../utility/koishi.constants'; } from '../utility/koishi.constants';
import { import {
CommandDefinitionFun,
CommandPutConfig, CommandPutConfig,
DoRegisterConfig, DoRegisterConfig,
EventName, EventName,
KoishiModulePlugin, KoishiModulePlugin,
OnContextFunction,
} from '../koishi.interfaces'; } from '../koishi.interfaces';
import { applySelector } from '../utility/koishi.utility'; import { applySelector } from '../utility/koishi.utility';
import _ from 'lodash'; import _ from 'lodash';
import { KoishiContextService } from './koishi-context.service'; import { KoishiContextService } from './koishi-context.service';
import { Module } from '@nestjs/core/injector/module'; import { Module } from '@nestjs/core/injector/module';
import { KoishiMetadataFetcherService } from '../koishi-metadata-fetcher/koishi-metadata-fetcher.service';
@Injectable() @Injectable()
export class KoishiMetascanService { export class KoishiMetascanService {
constructor( constructor(
private readonly metadataScanner: MetadataScanner, private readonly metadataScanner: MetadataScanner,
private readonly reflector: Reflector,
private readonly moduleRef: ModuleRef, private readonly moduleRef: ModuleRef,
private readonly moduleContainer: ModulesContainer, private readonly moduleContainer: ModulesContainer,
private readonly ctxService: KoishiContextService, private readonly ctxService: KoishiContextService,
private readonly metaFetcher: KoishiMetadataFetcherService,
) {} ) {}
private preRegisterCommandActionArg(config: CommandPutConfig, cmd: Command) { private preRegisterCommandActionArg(config: CommandPutConfig, cmd: Command) {
...@@ -119,32 +111,19 @@ export class KoishiMetascanService { ...@@ -119,32 +111,19 @@ export class KoishiMetascanService {
methodKey: string, methodKey: string,
) { ) {
const methodFun: (...args: any[]) => any = instance[methodKey]; const methodFun: (...args: any[]) => any = instance[methodKey];
const regData: DoRegisterConfig = this.reflector.get( const regData = this.metaFetcher.getMetadata(KoishiDoRegister, methodFun);
KoishiDoRegister,
methodFun,
);
if (!regData) { if (!regData) {
return; return;
} }
let baseContext = ctx; let baseContext = ctx;
const instanceContextFilters: OnContextFunction[] = this.reflector.get( const contextFilters = this.metaFetcher.getPropertyMetadataArray(
KoishiOnContextScope,
instance.constructor,
);
if (instanceContextFilters) {
for (const filter of instanceContextFilters) {
baseContext = filter(baseContext) || baseContext;
}
}
const methodContextFilters: OnContextFunction[] = this.reflector.get(
KoishiOnContextScope, KoishiOnContextScope,
methodFun, instance,
methodKey,
); );
if (methodContextFilters) { for (const filter of contextFilters) {
for (const filter of methodContextFilters) {
baseContext = filter(baseContext) || baseContext; baseContext = filter(baseContext) || baseContext;
} }
}
switch (regData.type) { switch (regData.type) {
case 'middleware': case 'middleware':
const { data: midPrepend } = regData as DoRegisterConfig<'middleware'>; const { data: midPrepend } = regData as DoRegisterConfig<'middleware'>;
...@@ -184,9 +163,9 @@ export class KoishiMetascanService { ...@@ -184,9 +163,9 @@ export class KoishiMetascanService {
commandData.desc, commandData.desc,
commandData.config, commandData.config,
); );
const commandDefs: CommandDefinitionFun[] = this.reflector.get( const commandDefs = this.metaFetcher.getMetadataArray(
KoishiCommandDefinition, KoishiCommandDefinition,
methodFun, methodFun(),
); );
if (commandDefs) { if (commandDefs) {
for (const commandDef of commandDefs) { for (const commandDef of commandDefs) {
...@@ -234,16 +213,14 @@ export class KoishiMetascanService { ...@@ -234,16 +213,14 @@ export class KoishiMetascanService {
} }
private scanInstanceForProvidingContextService(ctx: Context, instance: any) { private scanInstanceForProvidingContextService(ctx: Context, instance: any) {
const providingServiceNames: string[] = this.reflector.get( const providingServiceNames = this.metaFetcher.getMetadataArray(
KoishiServiceProvideSym, KoishiServiceProvideSym,
instance.constructor, instance.constructor,
); );
if (providingServiceNames) {
for (const name of providingServiceNames) { for (const name of providingServiceNames) {
ctx[name] = instance; ctx[name] = instance;
} }
} }
}
private scanInstanceForWireContextService(ctx: Context, instance: any) { private scanInstanceForWireContextService(ctx: Context, instance: any) {
const instanceClass = instance.constructor; const instanceClass = instance.constructor;
......
// Injections // Injections
import {
CommandDefinitionFun,
DoRegisterConfig,
OnContextFunction,
} from '../koishi.interfaces';
import { Context } from 'koishi';
export const KOISHI_MODULE_OPTIONS = 'KOISHI_MODULE_OPTIONS'; export const KOISHI_MODULE_OPTIONS = 'KOISHI_MODULE_OPTIONS';
export const KOISHI_CONTEXT = 'KOISHI_CONTEXT'; export const KOISHI_CONTEXT = 'KOISHI_CONTEXT';
...@@ -6,8 +13,25 @@ export const KOISHI_CONTEXT = 'KOISHI_CONTEXT'; ...@@ -6,8 +13,25 @@ export const KOISHI_CONTEXT = 'KOISHI_CONTEXT';
export const KoishiOnContextScope = 'KoishiOnContextScope'; export const KoishiOnContextScope = 'KoishiOnContextScope';
export const KoishiDoRegister = 'KoishiDoRegister'; export const KoishiDoRegister = 'KoishiDoRegister';
export const KoishiCommandDefinition = 'KoishiCommandDefinition'; export const KoishiCommandDefinition = 'KoishiCommandDefinition';
export const KoishiCommandPutDef = Symbol('KoishiCommandPutDef'); export const KoishiCommandPutDef = 'KoishiCommandPutDef';
export const KoishiServiceWireProperty = Symbol('KoishiServiceWireProperty'); export const KoishiServiceWireProperty = 'KoishiServiceWireProperty';
export const KoishiServiceWireKeys = Symbol('KoishiServiceWireKeys'); export const KoishiServiceWireKeys = 'KoishiServiceWireKeys';
export const KoishiServiceProvideSym = 'KoishiServiceProvideSym'; export const KoishiServiceProvideSym = 'KoishiServiceProvideSym';
// metadata map
export interface MetadataArrayMap {
KoishiOnContextScope: OnContextFunction;
KoishiCommandDefinition: CommandDefinitionFun;
KoishiServiceProvideSym: keyof Context.Services;
}
export interface MetadataMap {
KoishiDoRegister: DoRegisterConfig;
}
export type MetadataGenericMap = {
[K in keyof MetadataArrayMap]: MetadataArrayMap[K][];
} &
MetadataMap;
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