Commit aab01e37 authored by nanahira's avatar nanahira

multi plugin

parent 4603929c
......@@ -15,7 +15,7 @@
"koishi-decorators": "^2.0.0",
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13",
"schemastery-gen": "^3.1.4",
"schemastery-gen": "^3.1.6",
"typed-reflector": "^1.0.10"
},
"devDependencies": {
......@@ -38,7 +38,7 @@
"ws": "^8.2.3"
},
"peerDependencies": {
"koishi": "^4.6.0",
"koishi": "^4.6.1",
"schemastery": "^3.1.0"
}
},
......@@ -1028,15 +1028,15 @@
}
},
"node_modules/@koishijs/core": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@koishijs/core/-/core-4.6.0.tgz",
"integrity": "sha512-m+K2h/Oqmpcw39dQhJ/D9MBmwnWNUf9uFqymJ94+nP4CR7rcM1DTWNiaMGshGUqNu+s4q0ildoEDlQrE4hVuWA==",
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/@koishijs/core/-/core-4.6.1.tgz",
"integrity": "sha512-2HzdUi76YSLFZYpPXcmEwwVyHQLPF8BL0GJR6PuCYdOYfHykzwA5NmqOGx29EyeuYzs8sS6yr25IQktxMYqsdg==",
"peer": true,
"dependencies": {
"@koishijs/utils": "^5.4.0",
"cosmotype": "^1.0.3",
"@koishijs/utils": "^5.4.1",
"cosmotype": "^1.0.6",
"fastest-levenshtein": "^1.0.12",
"ns-require": "^1.1.0"
"ns-require": "^1.1.2"
},
"engines": {
"node": ">=12.0.0"
......@@ -1062,15 +1062,15 @@
"peer": true
},
"node_modules/@koishijs/utils": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@koishijs/utils/-/utils-5.4.0.tgz",
"integrity": "sha512-w5SHArw032cXVtxp5nXkc5jzP6Fn3LrF7FQTanPnOgmjGv/AIOAKfJ6bqaOUsSg+ttcK3iO8xs65W6XsNz3g7g==",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/@koishijs/utils/-/utils-5.4.1.tgz",
"integrity": "sha512-M3L9KqtdTyCzQK1LxTtp7QCucc75IA2vRwnYJA1gXMAxPC3SoEjUVmsk/oNFBSknmfADdViI5mFJtUXMCpJW1g==",
"peer": true,
"dependencies": {
"@koishijs/segment": "^1.1.1",
"cosmokit": "^1.1.1",
"reggol": "^1.0.1",
"schemastery": "^3.3.2",
"cosmokit": "^1.1.2",
"reggol": "^1.0.2",
"schemastery": "^3.3.3",
"supports-color": "^8.1.1"
}
},
......@@ -2295,19 +2295,19 @@
"peer": true
},
"node_modules/cosmokit": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cosmokit/-/cosmokit-1.1.1.tgz",
"integrity": "sha512-+f8x9pFGIc7I6HTObS90dq2K5YsI4U3Me4l9OminU9woVtF9Sv3CAHb5vKbFZ93XpTFctAQ6qAVSGjkGvGI9iw==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cosmokit/-/cosmokit-1.1.2.tgz",
"integrity": "sha512-cSNrcyxZ3GT+tjSlUzWIzMiK7Wndq1Nm/2tlRhT65RXltSIcH5zaHdmnz1TnIhLuOViaO9qfSdnRPzxNkxMv0g==",
"peer": true
},
"node_modules/cosmotype": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cosmotype/-/cosmotype-1.0.3.tgz",
"integrity": "sha512-JykvyDjyjaDjycm8CcK8GD4Xt6/Glu4pJU9uJ5lsDuE5B5bdmAykiTPMHfs+Is8QUsNaDKpsHfxtxCUBDPYgdw==",
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/cosmotype/-/cosmotype-1.0.9.tgz",
"integrity": "sha512-ot2m5LYBj9UNFvYpQNQ28hWYDG4GWmym094us2HNn6qgYzvALmjs4FxEVBsjA+VBnIf3ykuMGRYcex5cqZTvJQ==",
"peer": true,
"dependencies": {
"cosmokit": "^1.1.1",
"ns-require": "^1.1.0"
"cosmokit": "^1.1.2",
"ns-require": "^1.1.2"
}
},
"node_modules/cosmotype-decorators": {
......@@ -4770,14 +4770,14 @@
}
},
"node_modules/koishi": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/koishi/-/koishi-4.6.0.tgz",
"integrity": "sha512-QhjFWTGhrFnYfpVg4dNNxgHER38zSij3nyM/RB3YrLTM4VwImVk5unpgg0QryViwWxSYM4zJ0YUoys4A9jgG6A==",
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/koishi/-/koishi-4.6.1.tgz",
"integrity": "sha512-9NtcXrIKLN8AG9zEf3GzweSiHQubew0AWfjaci0grIxy760T77D8iLVsDbVhzmGSnc26WOR2q3CMFdRmE2igVA==",
"peer": true,
"dependencies": {
"@koa/router": "^10.1.1",
"@koishijs/core": "^4.6.0",
"@koishijs/utils": "^5.4.0",
"@koishijs/core": "^4.6.1",
"@koishijs/utils": "^5.4.1",
"@types/koa": "*",
"@types/koa__router": "*",
"@types/ws": "^8.5.3",
......@@ -5092,9 +5092,9 @@
}
},
"node_modules/ns-require": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/ns-require/-/ns-require-1.1.0.tgz",
"integrity": "sha512-Iw349zwWNgkGZjYJtruf+BXUe8YHOiMZE0iUNffvpt/A1yTSabTnpBMQ0zNl65G1LhpzwCo1KMCqjmJF0z8O6g==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/ns-require/-/ns-require-1.1.2.tgz",
"integrity": "sha512-GUF6I1hWDsGx1cA9FW27KIRAlkMel2UZagR39dVNPAPBgwWK1Ez0XB96WEz2OFcwHsCORI9h75dEZueHqZ/1pA==",
"peer": true
},
"node_modules/nwsapi": {
......@@ -5679,12 +5679,12 @@
}
},
"node_modules/reggol": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/reggol/-/reggol-1.0.1.tgz",
"integrity": "sha512-ZMOp3rZG6YQFVp/DC+BgFZaXSQcxHDayCmo7cL/kGujsSEoUzee0VJq1KCe9sgNt0qsM6JzkuSlj/+5SmmoO7Q==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/reggol/-/reggol-1.0.2.tgz",
"integrity": "sha512-BP7gx5nUBntWChG4x/yf7xLdpxy1R5PMtF/LJlOsz+XkWtip4YVNkQp2Flmio9hXSc2UxrwUyP0WrQ1M/FFWXw==",
"peer": true,
"dependencies": {
"cosmokit": "^1.1.0",
"cosmokit": "^1.1.2",
"supports-color": "^8.1.1"
}
},
......@@ -5844,25 +5844,25 @@
}
},
"node_modules/schemastery": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/schemastery/-/schemastery-3.3.2.tgz",
"integrity": "sha512-Z1C850OPtNEBs+D4QBPdC+Wu1t6Fn1BrOJILRHs2b+I/u61hUKP2vIPMAXFLvmmONnwqAW8ksPdCD6Zz9n8zhg==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/schemastery/-/schemastery-3.3.3.tgz",
"integrity": "sha512-DwRsse6C+Qao90P/Bz+4G3gmAjM3he/VgHk3TykmEWv3KFqvwmqEn61SF3BPaTPP0L77a5Kc6q4+KQvdN1bBqA==",
"peer": true,
"dependencies": {
"cosmokit": "^1.1.0"
"cosmokit": "^1.1.2"
}
},
"node_modules/schemastery-gen": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/schemastery-gen/-/schemastery-gen-3.1.4.tgz",
"integrity": "sha512-zhM5A2p/SdPKe8ouObCYSOA3k5I1CpbOfSvv8DWp7kCbVnSgfOMSBCB4Yue3/D81+MAE2re93nSt7k/Tolz3mQ==",
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/schemastery-gen/-/schemastery-gen-3.1.6.tgz",
"integrity": "sha512-UiYsiuvj830k2IzznWx/+Ed9+j1+XwMZ1zfctpy6+rHe6Se0IrulBsh2XDmI2uDslFtd6HfjIi5BJksbVvXQ/w==",
"dependencies": {
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13",
"typed-reflector": "^1.0.10"
},
"peerDependencies": {
"schemastery": "^3.3.2"
"schemastery": "^3.3.3"
}
},
"node_modules/semver": {
......@@ -7627,15 +7627,15 @@
}
},
"@koishijs/core": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/@koishijs/core/-/core-4.6.0.tgz",
"integrity": "sha512-m+K2h/Oqmpcw39dQhJ/D9MBmwnWNUf9uFqymJ94+nP4CR7rcM1DTWNiaMGshGUqNu+s4q0ildoEDlQrE4hVuWA==",
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/@koishijs/core/-/core-4.6.1.tgz",
"integrity": "sha512-2HzdUi76YSLFZYpPXcmEwwVyHQLPF8BL0GJR6PuCYdOYfHykzwA5NmqOGx29EyeuYzs8sS6yr25IQktxMYqsdg==",
"peer": true,
"requires": {
"@koishijs/utils": "^5.4.0",
"cosmotype": "^1.0.3",
"@koishijs/utils": "^5.4.1",
"cosmotype": "^1.0.6",
"fastest-levenshtein": "^1.0.12",
"ns-require": "^1.1.0"
"ns-require": "^1.1.2"
}
},
"@koishijs/plugin-adapter-onebot": {
......@@ -7655,15 +7655,15 @@
"peer": true
},
"@koishijs/utils": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/@koishijs/utils/-/utils-5.4.0.tgz",
"integrity": "sha512-w5SHArw032cXVtxp5nXkc5jzP6Fn3LrF7FQTanPnOgmjGv/AIOAKfJ6bqaOUsSg+ttcK3iO8xs65W6XsNz3g7g==",
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/@koishijs/utils/-/utils-5.4.1.tgz",
"integrity": "sha512-M3L9KqtdTyCzQK1LxTtp7QCucc75IA2vRwnYJA1gXMAxPC3SoEjUVmsk/oNFBSknmfADdViI5mFJtUXMCpJW1g==",
"peer": true,
"requires": {
"@koishijs/segment": "^1.1.1",
"cosmokit": "^1.1.1",
"reggol": "^1.0.1",
"schemastery": "^3.3.2",
"cosmokit": "^1.1.2",
"reggol": "^1.0.2",
"schemastery": "^3.3.3",
"supports-color": "^8.1.1"
},
"dependencies": {
......@@ -8649,19 +8649,19 @@
"peer": true
},
"cosmokit": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/cosmokit/-/cosmokit-1.1.1.tgz",
"integrity": "sha512-+f8x9pFGIc7I6HTObS90dq2K5YsI4U3Me4l9OminU9woVtF9Sv3CAHb5vKbFZ93XpTFctAQ6qAVSGjkGvGI9iw==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/cosmokit/-/cosmokit-1.1.2.tgz",
"integrity": "sha512-cSNrcyxZ3GT+tjSlUzWIzMiK7Wndq1Nm/2tlRhT65RXltSIcH5zaHdmnz1TnIhLuOViaO9qfSdnRPzxNkxMv0g==",
"peer": true
},
"cosmotype": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/cosmotype/-/cosmotype-1.0.3.tgz",
"integrity": "sha512-JykvyDjyjaDjycm8CcK8GD4Xt6/Glu4pJU9uJ5lsDuE5B5bdmAykiTPMHfs+Is8QUsNaDKpsHfxtxCUBDPYgdw==",
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/cosmotype/-/cosmotype-1.0.9.tgz",
"integrity": "sha512-ot2m5LYBj9UNFvYpQNQ28hWYDG4GWmym094us2HNn6qgYzvALmjs4FxEVBsjA+VBnIf3ykuMGRYcex5cqZTvJQ==",
"peer": true,
"requires": {
"cosmokit": "^1.1.1",
"ns-require": "^1.1.0"
"cosmokit": "^1.1.2",
"ns-require": "^1.1.2"
}
},
"cosmotype-decorators": {
......@@ -10512,14 +10512,14 @@
}
},
"koishi": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/koishi/-/koishi-4.6.0.tgz",
"integrity": "sha512-QhjFWTGhrFnYfpVg4dNNxgHER38zSij3nyM/RB3YrLTM4VwImVk5unpgg0QryViwWxSYM4zJ0YUoys4A9jgG6A==",
"version": "4.6.1",
"resolved": "https://registry.npmjs.org/koishi/-/koishi-4.6.1.tgz",
"integrity": "sha512-9NtcXrIKLN8AG9zEf3GzweSiHQubew0AWfjaci0grIxy760T77D8iLVsDbVhzmGSnc26WOR2q3CMFdRmE2igVA==",
"peer": true,
"requires": {
"@koa/router": "^10.1.1",
"@koishijs/core": "^4.6.0",
"@koishijs/utils": "^5.4.0",
"@koishijs/core": "^4.6.1",
"@koishijs/utils": "^5.4.1",
"@types/koa": "*",
"@types/koa__router": "*",
"@types/ws": "^8.5.3",
......@@ -10764,9 +10764,9 @@
}
},
"ns-require": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/ns-require/-/ns-require-1.1.0.tgz",
"integrity": "sha512-Iw349zwWNgkGZjYJtruf+BXUe8YHOiMZE0iUNffvpt/A1yTSabTnpBMQ0zNl65G1LhpzwCo1KMCqjmJF0z8O6g==",
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/ns-require/-/ns-require-1.1.2.tgz",
"integrity": "sha512-GUF6I1hWDsGx1cA9FW27KIRAlkMel2UZagR39dVNPAPBgwWK1Ez0XB96WEz2OFcwHsCORI9h75dEZueHqZ/1pA==",
"peer": true
},
"nwsapi": {
......@@ -11200,12 +11200,12 @@
"dev": true
},
"reggol": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/reggol/-/reggol-1.0.1.tgz",
"integrity": "sha512-ZMOp3rZG6YQFVp/DC+BgFZaXSQcxHDayCmo7cL/kGujsSEoUzee0VJq1KCe9sgNt0qsM6JzkuSlj/+5SmmoO7Q==",
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/reggol/-/reggol-1.0.2.tgz",
"integrity": "sha512-BP7gx5nUBntWChG4x/yf7xLdpxy1R5PMtF/LJlOsz+XkWtip4YVNkQp2Flmio9hXSc2UxrwUyP0WrQ1M/FFWXw==",
"peer": true,
"requires": {
"cosmokit": "^1.1.0",
"cosmokit": "^1.1.2",
"supports-color": "^8.1.1"
},
"dependencies": {
......@@ -11315,18 +11315,18 @@
}
},
"schemastery": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/schemastery/-/schemastery-3.3.2.tgz",
"integrity": "sha512-Z1C850OPtNEBs+D4QBPdC+Wu1t6Fn1BrOJILRHs2b+I/u61hUKP2vIPMAXFLvmmONnwqAW8ksPdCD6Zz9n8zhg==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/schemastery/-/schemastery-3.3.3.tgz",
"integrity": "sha512-DwRsse6C+Qao90P/Bz+4G3gmAjM3he/VgHk3TykmEWv3KFqvwmqEn61SF3BPaTPP0L77a5Kc6q4+KQvdN1bBqA==",
"peer": true,
"requires": {
"cosmokit": "^1.1.0"
"cosmokit": "^1.1.2"
}
},
"schemastery-gen": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/schemastery-gen/-/schemastery-gen-3.1.4.tgz",
"integrity": "sha512-zhM5A2p/SdPKe8ouObCYSOA3k5I1CpbOfSvv8DWp7kCbVnSgfOMSBCB4Yue3/D81+MAE2re93nSt7k/Tolz3mQ==",
"version": "3.1.6",
"resolved": "https://registry.npmjs.org/schemastery-gen/-/schemastery-gen-3.1.6.tgz",
"integrity": "sha512-UiYsiuvj830k2IzznWx/+Ed9+j1+XwMZ1zfctpy6+rHe6Se0IrulBsh2XDmI2uDslFtd6HfjIi5BJksbVvXQ/w==",
"requires": {
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13",
......
......@@ -54,7 +54,7 @@
"koishi-decorators": "^2.0.0",
"lodash": "^4.17.21",
"reflect-metadata": "^0.1.13",
"schemastery-gen": "^3.1.4",
"schemastery-gen": "^3.1.6",
"typed-reflector": "^1.0.10"
},
"jest": {
......@@ -75,7 +75,7 @@
"testEnvironment": "node"
},
"peerDependencies": {
"koishi": "^4.6.0",
"koishi": "^4.6.1",
"schemastery": "^3.1.0"
}
}
import 'reflect-metadata';
import { App, Context, Flatten, Keys, Selection, Tables } from 'koishi';
import { App, Context, Flatten, Keys, Schema, Selection, Tables } from 'koishi';
import { Metadata } from './meta/metadata.decorators';
import {
Condition,
......@@ -15,6 +15,7 @@ import {
} from './def';
import { TopLevelAction } from 'koishi-decorators';
import { ModelClassType, ModelRegistrar } from 'cosmotype-decorators';
import { ClassType } from 'schemastery-gen';
// Export all koishi-decorator decorators
......@@ -124,6 +125,9 @@ export function UsingService(
};
}
export const PluginSchema = (schema: Schema | ClassType<any>) =>
Metadata.set('KoishiPredefineSchema', schema);
export const If = <T>(func: Condition<boolean, T>): MethodDecorator =>
Metadata.append('KoishiIf', func);
......
// metadatas
import { Context } from 'koishi';
import { Context, Schema } from 'koishi';
import { Condition, ProvideDefinition, SystemInjectFun } from './interfaces';
import { ClassType } from 'schemastery-gen';
export const KoishiServiceInjectSym = 'KoishiServiceInjectSym';
export const KoishiServiceInjectSymKeys = 'KoishiServiceInjectSymKeys';
......@@ -24,4 +25,5 @@ export interface MetadataArrayMap {
export interface MetadataMap {
KoishiServiceInjectSym: keyof Context.Services;
KoishiSystemInjectSym: SystemInjectFun;
KoishiPredefineSchema: Schema | ClassType<any>;
}
......@@ -22,3 +22,23 @@ export type Condition<R, T = any> = (
config: T extends { config: infer C } ? C : any,
ctx: Context,
) => R;
export interface Instances<T> {
instances: T[];
}
export type AnyClassType = { new (...args: any[]): any };
export type TypeFromClass<T> = T extends { new (...args: any[]): infer U }
? U
: never;
export type ParamsFromClass<T> = T extends { new (...args: infer U): any }
? U
: never;
export type MultiPluginConfig<Inner, Outer> = Instances<Inner> & Outer;
export type ClassPluginConfig<
P extends new (ctx: Context, config: any) => any,
> = P extends new (ctx: Context, config: infer C) => any ? C : never;
import { ClonePlugin } from './utility/clone-plugin';
import { Context } from 'koishi';
import { PartialDeep } from './base-plugin';
import { ClassPluginConfig, MultiPluginConfig, TypeFromClass } from './def';
import { ClassType } from 'schemastery-gen';
import { ToInstancesConfig } from './utility/to-instance-config';
import Schema from 'schemastery';
import { InjectConfig, PluginSchema, UsingService } from './decorators';
import { UseEvent } from 'koishi-decorators';
export class MultiInstancePluginFramework<
InnerPlugin extends new (ctx: Context, config: any) => any,
OuterConfig,
> {
constructor(
public ctx: Context,
config: MultiPluginConfig<
ClassPluginConfig<InnerPlugin>,
PartialDeep<OuterConfig>
>,
) {}
@InjectConfig()
config: MultiPluginConfig<ClassPluginConfig<InnerPlugin>, OuterConfig>;
instances: TypeFromClass<InnerPlugin>[] = [];
_getInnerPlugin(): new (
ctx: Context,
config: ClassPluginConfig<InnerPlugin>,
) => any {
throw new Error(`Not implemented`);
}
_registerInstances() {
const innerPlugin = this._getInnerPlugin();
for (let i = 0; i < this.config.instances.length; i++) {
const clonedInnerPlugin = ClonePlugin(
innerPlugin,
`${innerPlugin.name}_instance_${i}`,
(instance) => this.instances.push(instance),
);
this.ctx.plugin(clonedInnerPlugin, this.config.instances[i]);
}
}
@UseEvent('dispose')
_onThingsDispose() {
delete this.instances;
}
onApply() {
this._registerInstances();
}
}
export function MultiInstancePlugin<
InnerPlugin extends new (ctx: Context, config: any) => any,
OuterConfig,
>(innerPlugin: InnerPlugin, outerConfig?: ClassType<OuterConfig>) {
const pluginClass = class SpecificMultiInstancePlugin extends MultiInstancePluginFramework<
InnerPlugin,
OuterConfig
> {
_getInnerPlugin() {
return innerPlugin;
}
};
const schema = ToInstancesConfig(
(innerPlugin['Config'] ||
innerPlugin['schema'] ||
Schema.any()) as ClassType<ClassPluginConfig<InnerPlugin>>,
outerConfig,
);
if (schema) {
PluginSchema(schema)(pluginClass);
}
if (innerPlugin['using']) {
UsingService(...(innerPlugin['using'] as (keyof Context.Services)[]))(
pluginClass,
);
}
return pluginClass;
}
......@@ -50,14 +50,12 @@ export function DefinePlugin<T = any>(
return function <
C extends {
new (...args: any[]): any;
} & KoishiPluginRegistrationOptions<any>,
} & KoishiPluginRegistrationOptions<T>,
>(originalClass: C) {
const schemaType =
options.schema || reflector.get('KoishiPredefineSchema', originalClass);
const newClass = class extends originalClass implements PluginClass {
static Config =
options.schema &&
((options.schema as Schema).type
? (options.schema as Schema<Partial<T>, T>)
: SchemaClass(options.schema as ClassType<T>));
static Config = schemaType ? SchemaClass(schemaType) : undefined;
static get using() {
const list = reflector
.getArray(KoishiAddUsingList, originalClass)
......@@ -224,14 +222,12 @@ export function DefinePlugin<T = any>(
this._initializePluginClass();
}
};
if (options.name) {
Object.defineProperty(newClass, 'name', {
enumerable: true,
configurable: true,
writable: true,
value: options.name,
});
}
Object.defineProperty(newClass, 'name', {
enumerable: true,
configurable: true,
writable: true,
value: options.name || originalClass.name,
});
return newClass;
};
}
......
import { TypeFromClass } from '../def';
export function ClonePlugin<P extends { new (...args: any[]): any }>(
target: P,
name: string,
callback?: (instance: TypeFromClass<P>) => void,
): P {
const clonedPlugin = class extends target {
constructor(...args: any[]) {
super(...args);
if (callback) {
callback(this as any);
}
}
};
for (const property of ['Config', 'schema', 'using']) {
Object.defineProperty(clonedPlugin, property, {
enumerable: true,
configurable: true,
writable: true,
value: target[property],
});
}
Object.defineProperty(clonedPlugin, 'name', {
enumerable: true,
configurable: true,
writable: true,
value: name,
});
return clonedPlugin;
}
import { OriginalClassSym, SchemaClass, SchemaProperty } from 'schemastery-gen';
import {
AnyClassType,
Instances,
ParamsFromClass,
TypeFromClass,
} from '../def';
import { kSchema } from 'schemastery-gen/dist/src/utility/kschema';
export function ToInstancesConfig<Inner extends new (...args: any[]) => any>(
instanceConfig: Inner,
): new () => Instances<TypeFromClass<Inner>>;
export function ToInstancesConfig<
Inner extends new (...args: any[]) => any,
Outer extends new (...args: any[]) => any,
>(
instanceConfig: Inner,
outerConfig?: Outer,
): new (...args: ParamsFromClass<Outer>) => Instances<TypeFromClass<Inner>> &
TypeFromClass<Outer>;
export function ToInstancesConfig<
Inner extends AnyClassType,
Outer extends AnyClassType,
>(
instanceConfig: Inner,
outerConfig?: Outer,
): new (...args: ParamsFromClass<Outer>) => Instances<TypeFromClass<Inner>> &
TypeFromClass<Outer> {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
outerConfig ??= class EmptyConfig {};
if (outerConfig[OriginalClassSym]) {
outerConfig = outerConfig[OriginalClassSym];
}
const instanceConfigClass = class MixedInstancesConfig extends outerConfig {
instances: TypeFromClass<Inner>[];
};
SchemaProperty({
type: SchemaClass(instanceConfig),
default: [],
array: true,
})(instanceConfigClass.prototype, 'instances');
return instanceConfigClass;
}
......@@ -4,6 +4,7 @@ import { Cache, Assets, Bot, Context } from 'koishi';
describe('InjectUsing', () => {
@UsingService('router')
@DefinePlugin({ using: ['database'] })
@UsingService('http')
class MyPlugin {
@Inject(true)
cache: Cache;
......@@ -18,11 +19,12 @@ describe('InjectUsing', () => {
it('Should include injected using services', () => {
const usingList = (MyPlugin as any).using as (keyof Context.Services)[];
expect(usingList).toBeInstanceOf(Array);
expect(usingList.length).toEqual(4);
expect(usingList.length).toEqual(5);
expect(usingList.includes('database')).toEqual(true);
expect(usingList.includes('assets')).toEqual(true);
expect(usingList.includes('cache')).toEqual(true);
expect(usingList.includes('router')).toEqual(true);
expect(usingList.includes('bots')).toEqual(false);
expect(usingList.includes('http')).toEqual(true);
});
});
import { DefinePlugin } from '../src/register';
import { RegisterSchema, SchemaProperty } from 'schemastery-gen';
import { BasePlugin } from '../src/base-plugin';
import { UseCommand } from 'koishi-decorators';
import { MultiInstancePlugin } from '../src/multi-plugin';
import { App } from 'koishi';
class MessageConfig {
@SchemaProperty()
msg: string;
getMsg() {
return this.msg;
}
}
@RegisterSchema()
class InnerMessageConfig extends MessageConfig {}
@RegisterSchema()
class OuterMessageConfig extends MessageConfig {}
@DefinePlugin({ schema: InnerMessageConfig })
class Inner extends BasePlugin<InnerMessageConfig> {
@UseCommand('message')
async onMessage() {
return this.config.getMsg();
}
}
@DefinePlugin()
class Outer extends MultiInstancePlugin(Inner, OuterMessageConfig) {
@UseCommand('message2')
async onMessage() {
return this.config.getMsg();
}
@UseCommand('message3')
async onInnerMessage() {
return this.instances[0].config.getMsg();
}
}
describe('It should register multi plugin instance', () => {
it('register command on condition', async () => {
const app = new App();
console.log(Inner['Config']);
console.log(Outer['Config']);
app.plugin(Outer, { msg: 'hello', instances: [{ msg: 'world' }] });
await app.start();
const innerCommand = app.command('message');
const outerCommand = app.command('message2');
const innerInnerCommand = app.command('message3');
expect(await innerCommand.execute({})).toBe('world');
expect(await outerCommand.execute({})).toBe('hello');
expect(await innerInnerCommand.execute({})).toBe('world');
});
});
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