Commit 5a47b011 authored by nanahira's avatar nanahira

remake with typed-reflector

parent 5c236463
...@@ -10,7 +10,8 @@ ...@@ -10,7 +10,8 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"koishi-utils-schemagen": "^1.1.9", "koishi-utils-schemagen": "^1.1.9",
"reflect-metadata": "^0.1.13" "reflect-metadata": "^0.1.13",
"typed-reflector": "^1.0.2"
}, },
"devDependencies": { "devDependencies": {
"@koishijs/plugin-adapter-onebot": "^4.0.0-beta.0", "@koishijs/plugin-adapter-onebot": "^4.0.0-beta.0",
...@@ -2941,6 +2942,14 @@ ...@@ -2941,6 +2942,14 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/typed-reflector": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/typed-reflector/-/typed-reflector-1.0.2.tgz",
"integrity": "sha512-dyhBLKAbT0O/OEIJXQw+IqAH9ddFk0iV4gJP5XvcgcfJ0xxyx4krx1visZtH8YoFe86piRKgO9VPs/Ktzfdb0w==",
"dependencies": {
"reflect-metadata": "^0.1.13"
}
},
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.4.4", "version": "4.4.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
...@@ -5267,6 +5276,14 @@ ...@@ -5267,6 +5276,14 @@
"mime-types": "~2.1.24" "mime-types": "~2.1.24"
} }
}, },
"typed-reflector": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/typed-reflector/-/typed-reflector-1.0.2.tgz",
"integrity": "sha512-dyhBLKAbT0O/OEIJXQw+IqAH9ddFk0iV4gJP5XvcgcfJ0xxyx4krx1visZtH8YoFe86piRKgO9VPs/Ktzfdb0w==",
"requires": {
"reflect-metadata": "^0.1.13"
}
},
"typescript": { "typescript": {
"version": "4.4.4", "version": "4.4.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.4.tgz",
......
...@@ -45,6 +45,7 @@ ...@@ -45,6 +45,7 @@
}, },
"dependencies": { "dependencies": {
"koishi-utils-schemagen": "^1.1.9", "koishi-utils-schemagen": "^1.1.9",
"reflect-metadata": "^0.1.13" "reflect-metadata": "^0.1.13",
"typed-reflector": "^1.0.2"
} }
} }
...@@ -2,6 +2,7 @@ import { ...@@ -2,6 +2,7 @@ import {
CommandDefinitionFun, CommandDefinitionFun,
CommandPutConfig, CommandPutConfig,
CommandPutConfigMap, CommandPutConfigMap,
DoRegisterConfig,
EventName, EventName,
GenerateMappingStruct, GenerateMappingStruct,
KoishiCommandDefinition, KoishiCommandDefinition,
...@@ -14,25 +15,18 @@ import { ...@@ -14,25 +15,18 @@ import {
KoishiServiceProvideSym, KoishiServiceProvideSym,
KoishiSystemInjectSym, KoishiSystemInjectSym,
KoishiSystemInjectSymKeys, KoishiSystemInjectSymKeys,
MetadataGenericMap, MetadataMap,
OnContextFunction, OnContextFunction,
Selection, Selection,
} from './def'; } from './def';
import 'reflect-metadata'; import 'reflect-metadata';
import { App, Argv, Command, Context, FieldCollector, Session } from 'koishi'; import { App, Argv, Command, Context, FieldCollector, Session } from 'koishi';
import {
AppendMetadata,
AppendMetadataUnique,
ConcatMetadata,
SetMetadata,
} from './meta/metadata.decorators';
import { PluginClass } from './register'; import { PluginClass } from './register';
import { Metadata } from './meta/metadata.decorators';
// Register methods // Register methods
export const DoRegister = ( export const DoRegister = (value: DoRegisterConfig): MethodDecorator =>
value: MetadataGenericMap['KoishiDoRegister'], Metadata.set(KoishiDoRegister, value, KoishiDoRegisterKeys);
): MethodDecorator =>
SetMetadata(KoishiDoRegister, value, KoishiDoRegisterKeys);
export const UseMiddleware = (prepend?: boolean): MethodDecorator => export const UseMiddleware = (prepend?: boolean): MethodDecorator =>
DoRegister(GenerateMappingStruct('middleware', prepend)); DoRegister(GenerateMappingStruct('middleware', prepend));
...@@ -78,7 +72,7 @@ export function UseCommand( ...@@ -78,7 +72,7 @@ export function UseCommand(
export const OnContext = ( export const OnContext = (
ctxFun: OnContextFunction, ctxFun: OnContextFunction,
): MethodDecorator & ClassDecorator => ): MethodDecorator & ClassDecorator =>
AppendMetadata(KoishiOnContextScope, ctxFun); Metadata.append(KoishiOnContextScope, ctxFun);
export const OnUser = (...values: string[]) => export const OnUser = (...values: string[]) =>
OnContext((ctx) => ctx.user(...values)); OnContext((ctx) => ctx.user(...values));
...@@ -104,7 +98,7 @@ export const OnSelection = (selection: Selection) => ...@@ -104,7 +98,7 @@ export const OnSelection = (selection: Selection) =>
// Command definition // Command definition
export const CommandDef = (def: CommandDefinitionFun): MethodDecorator => export const CommandDef = (def: CommandDefinitionFun): MethodDecorator =>
AppendMetadata(KoishiCommandDefinition, def); Metadata.append(KoishiCommandDefinition, def);
export const CommandDescription = (desc: string) => export const CommandDescription = (desc: string) =>
CommandDef((cmd) => { CommandDef((cmd) => {
...@@ -197,7 +191,7 @@ export function Inject(name?: keyof Context.Services): PropertyDecorator { ...@@ -197,7 +191,7 @@ export function Inject(name?: keyof Context.Services): PropertyDecorator {
} }
} }
const serviceName = name || (key as keyof Context.Services); const serviceName = name || (key as keyof Context.Services);
const dec = SetMetadata( const dec = Metadata.set(
KoishiServiceInjectSym, KoishiServiceInjectSym,
serviceName, serviceName,
KoishiServiceInjectSymKeys, KoishiServiceInjectSymKeys,
...@@ -211,11 +205,11 @@ export function Provide( ...@@ -211,11 +205,11 @@ export function Provide(
options?: Context.Options, options?: Context.Options,
): ClassDecorator { ): ClassDecorator {
Context.service(name, options); Context.service(name, options);
return AppendMetadataUnique(KoishiServiceProvideSym, name); return Metadata.appendUnique(KoishiServiceProvideSym, name);
} }
const InjectSystem = (fun: (obj: PluginClass) => any) => const InjectSystem = (fun: (obj: PluginClass) => any) =>
SetMetadata(KoishiSystemInjectSym, fun, KoishiSystemInjectSymKeys); Metadata.set(KoishiSystemInjectSym, fun, KoishiSystemInjectSymKeys);
export const InjectContext = (select?: Selection) => export const InjectContext = (select?: Selection) =>
InjectSystem((obj) => { InjectSystem((obj) => {
......
...@@ -142,24 +142,3 @@ export type CommandPutConfig< ...@@ -142,24 +142,3 @@ export type CommandPutConfig<
> = MappingStruct<CommandPutConfigMap, K>; > = MappingStruct<CommandPutConfigMap, K>;
export type CommandDefinitionFun = (cmd: Command) => Command; export type CommandDefinitionFun = (cmd: Command) => Command;
// metadata map
export type MetadataArrayValueMap = {
[K in keyof MetadataArrayMap]: MetadataArrayMap[K][];
};
export type MetadataGenericMap = MetadataArrayValueMap & MetadataMap;
export type MetadataArrayValue<
K extends keyof MetadataArrayValueMap
> = MetadataArrayValueMap[K];
export type MetadataKey = keyof MetadataArrayMap | keyof MetadataMap;
export type MetadataMapValue<
K extends MetadataKey
> = K extends keyof MetadataArrayValueMap
? MetadataArrayValue<K>
: K extends keyof MetadataMap
? MetadataMap[K]
: never;
import {
MetadataArrayMap,
MetadataArrayValue,
MetadataGenericMap,
MetadataMapValue,
} from '../def';
import 'reflect-metadata'; import 'reflect-metadata';
import { Reflector } from 'typed-reflector';
import { MetadataArrayMap, MetadataMap } from '../def';
export function getMetadata<K extends keyof MetadataGenericMap>( export const reflector = new Reflector<MetadataMap, MetadataArrayMap>();
metadataKey: K,
instance: any,
key?: string | symbol,
): MetadataMapValue<K> {
const instanceClass = instance.constructor;
if (key) {
return Reflect.getMetadata(metadataKey, instanceClass, key);
} else {
return Reflect.getMetadata(metadataKey, instanceClass);
}
}
export function getMetadataArray<K extends keyof MetadataArrayMap>(
metadataKey: K,
instance: any,
key?: string | symbol,
): MetadataArrayValue<K> {
return getMetadata(metadataKey, instance, key) || [];
}
export function getPropertyMetadata<K extends keyof MetadataArrayMap, I = any>(
metadataKey: K,
instance: I,
originalClass: any,
key: keyof I & (string | symbol),
): MetadataArrayValue<K> {
const valueFromClass = getMetadataArray(metadataKey, originalClass);
const valueFromProperty = getMetadataArray(metadataKey, instance, key);
return [...valueFromClass, ...valueFromProperty] as MetadataArrayValue<K>;
}
import {
MetadataArrayMap,
MetadataArrayValue,
MetadataArrayValueMap,
MetadataGenericMap,
MetadataKey,
} from '../def';
import 'reflect-metadata'; import 'reflect-metadata';
import { MetadataSetter } from 'typed-reflector';
import { MetadataArrayMap, MetadataMap } from '../def';
export type AllDecorators = MethodDecorator & export const Metadata = new MetadataSetter<MetadataMap, MetadataArrayMap>();
ClassDecorator &
PropertyDecorator;
function getMetadataInDecorator<
K extends MetadataKey,
VM extends Partial<MetadataGenericMap> = MetadataGenericMap
>(metaKey: K, target: any, key?: any): VM[K] {
const targetClass = target.constructor;
if (key) {
return Reflect.getMetadata(metaKey, targetClass, key);
} else {
return Reflect.getMetadata(metaKey, targetClass);
}
}
function setMetadataInDecorator<
K extends MetadataKey,
VM extends Partial<MetadataGenericMap> = MetadataGenericMap
>(metaKey: K, value: VM[K], target: any, key?: any) {
const targetClass = target.constructor;
if (key) {
return Reflect.defineMetadata(metaKey, value, targetClass, key);
} else {
return Reflect.defineMetadata(metaKey, value, targetClass);
}
}
function TransformMetadata<
K extends MetadataKey,
VM extends Partial<MetadataGenericMap> = MetadataGenericMap
>(
metadataKey: K,
metadataValueFun: (oldValue: VM[K]) => VM[K],
keysIndexMeta?: keyof MetadataArrayMap,
): AllDecorators {
return (target: any, key?: any, descriptor?: any) => {
const oldValue: VM[K] = getMetadataInDecorator(metadataKey, target, key);
const newValue = metadataValueFun(oldValue);
setMetadataInDecorator(metadataKey, newValue, target, key);
if (keysIndexMeta) {
const keysDec = AppendMetadataUnique(keysIndexMeta, key);
keysDec(target);
}
if (descriptor) {
return descriptor;
}
return target;
};
}
export const SetMetadata = <K extends keyof MetadataGenericMap>(
metadataKey: K,
metadataValue: MetadataGenericMap[K],
keysIndexMeta?: keyof MetadataArrayMap,
): AllDecorators =>
TransformMetadata<K>(metadataKey, () => metadataValue, keysIndexMeta);
export const AppendMetadata = <K extends keyof MetadataArrayMap>(
metadataKey: K,
metadataValue: MetadataArrayMap[K],
keysIndexMeta?: keyof MetadataArrayMap,
): AllDecorators =>
TransformMetadata<K, MetadataArrayValueMap>(
metadataKey,
(arr) => {
const newArr = arr || [];
newArr.push(metadataValue);
return newArr;
},
keysIndexMeta,
);
export const AppendMetadataUnique = <K extends keyof MetadataArrayMap>(
metadataKey: K,
metadataValue: MetadataArrayMap[K],
keysIndexMeta?: keyof MetadataArrayMap,
): AllDecorators =>
TransformMetadata<K, MetadataArrayValueMap>(
metadataKey,
(arr) => {
const newArr = arr || [];
if (newArr.includes(metadataValue)) {
return newArr;
}
newArr.push(metadataValue);
return newArr;
},
keysIndexMeta,
);
export const ConcatMetadata = <K extends keyof MetadataArrayValueMap>(
metadataKey: K,
metadataValue: MetadataArrayValue<K>,
keysIndexMeta?: keyof MetadataArrayMap,
): AllDecorators =>
TransformMetadata<K, MetadataArrayValueMap>(
metadataKey,
(arr) => ((arr || []) as any[]).concat(metadataValue),
keysIndexMeta,
);
...@@ -16,7 +16,7 @@ import { ...@@ -16,7 +16,7 @@ import {
Type, Type,
} from './def'; } from './def';
import { schemaFromClass, schemaTransform } from 'koishi-utils-schemagen'; import { schemaFromClass, schemaTransform } from 'koishi-utils-schemagen';
import { getMetadata, getMetadataArray } from './meta/meta-fetch'; import { reflector } from './meta/meta-fetch';
import { applySelector } from './utility/utility'; import { applySelector } from './utility/utility';
export interface KoishiPluginRegistrationOptions<T = any> { export interface KoishiPluginRegistrationOptions<T = any> {
...@@ -61,10 +61,10 @@ export function KoishiPlugin<T = any>( ...@@ -61,10 +61,10 @@ export function KoishiPlugin<T = any>(
_handleSystemInjections() { _handleSystemInjections() {
// console.log('Handling system injection'); // console.log('Handling system injection');
const injectKeys = getMetadataArray(KoishiSystemInjectSymKeys, this); const injectKeys = reflector.getArray(KoishiSystemInjectSymKeys, this);
for (const key of injectKeys) { for (const key of injectKeys) {
// console.log(`Processing ${key}`); // console.log(`Processing ${key}`);
const valueFunction = getMetadata(KoishiSystemInjectSym, this, key); const valueFunction = reflector.get(KoishiSystemInjectSym, this, key);
Object.defineProperty(this, key, { Object.defineProperty(this, key, {
configurable: true, configurable: true,
enumerable: true, enumerable: true,
...@@ -75,10 +75,10 @@ export function KoishiPlugin<T = any>( ...@@ -75,10 +75,10 @@ export function KoishiPlugin<T = any>(
_handleServiceInjections() { _handleServiceInjections() {
// console.log('Handling service injection'); // console.log('Handling service injection');
const injectKeys = getMetadataArray(KoishiServiceInjectSymKeys, this); const injectKeys = reflector.getArray(KoishiServiceInjectSymKeys, this);
for (const key of injectKeys) { for (const key of injectKeys) {
// console.log(`Processing ${key}`); // console.log(`Processing ${key}`);
const name = getMetadata(KoishiServiceInjectSym, this, key); const name = reflector.get(KoishiServiceInjectSym, this, key);
Object.defineProperty(this, key, { Object.defineProperty(this, key, {
enumerable: true, enumerable: true,
configurable: true, configurable: true,
...@@ -171,14 +171,14 @@ export function KoishiPlugin<T = any>( ...@@ -171,14 +171,14 @@ export function KoishiPlugin<T = any>(
async _registerDeclarationsFor(methodKey: keyof C & string) { async _registerDeclarationsFor(methodKey: keyof C & string) {
// console.log(`Handling declaration for ${methodKey}`); // console.log(`Handling declaration for ${methodKey}`);
const regData = getMetadata(KoishiDoRegister, this, methodKey); const regData = reflector.get(KoishiDoRegister, this, methodKey);
if (!regData) { if (!regData) {
return; return;
} }
// console.log(`Type: ${regData.type}`); // console.log(`Type: ${regData.type}`);
const baseContext = getContextFromFilters( const baseContext = getContextFromFilters(
this.__ctx, this.__ctx,
getMetadataArray(KoishiOnContextScope, this, methodKey), reflector.getArray(KoishiOnContextScope, this, methodKey),
); );
switch (regData.type) { switch (regData.type) {
case 'middleware': case 'middleware':
...@@ -224,7 +224,7 @@ export function KoishiPlugin<T = any>( ...@@ -224,7 +224,7 @@ export function KoishiPlugin<T = any>(
commandData.desc, commandData.desc,
commandData.config, commandData.config,
); );
const commandDefs = getMetadataArray( const commandDefs = reflector.getArray(
KoishiCommandDefinition, KoishiCommandDefinition,
this, this,
methodKey, methodKey,
...@@ -254,7 +254,7 @@ export function KoishiPlugin<T = any>( ...@@ -254,7 +254,7 @@ export function KoishiPlugin<T = any>(
} }
async _registerDeclarations() { async _registerDeclarations() {
const methodKeys = getMetadataArray( const methodKeys = reflector.getArray(
KoishiDoRegisterKeys, KoishiDoRegisterKeys,
this, this,
) as (keyof C & string)[]; ) as (keyof C & string)[];
...@@ -268,7 +268,7 @@ export function KoishiPlugin<T = any>( ...@@ -268,7 +268,7 @@ export function KoishiPlugin<T = any>(
_handleServiceProvide(connect = true) { _handleServiceProvide(connect = true) {
// console.log(`Handling service provide`); // console.log(`Handling service provide`);
const providingServices = getMetadataArray( const providingServices = reflector.getArray(
KoishiServiceProvideSym, KoishiServiceProvideSym,
originalClass, originalClass,
); );
...@@ -307,7 +307,7 @@ export function KoishiPlugin<T = any>( ...@@ -307,7 +307,7 @@ export function KoishiPlugin<T = any>(
constructor(...args: any[]) { constructor(...args: any[]) {
const originalCtx: Context = args[0]; const originalCtx: Context = args[0];
const rawConfig = args[1]; const rawConfig = args[1];
const contextFilters = getMetadataArray( const contextFilters = reflector.getArray(
KoishiOnContextScope, KoishiOnContextScope,
originalClass, originalClass,
); );
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "dist", "outDir": "dist",
"module": "commonjs", "module": "commonjs",
"target": "es2021", "target": "es2020",
"esModuleInterop": true, "esModuleInterop": true,
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
......
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