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