Commit e16035a5 authored by nanahira's avatar nanahira

workaround inner plugin

parent 4d3981a1
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
}, },
"devDependencies": { "devDependencies": {
"@koishijs/plugin-adapter-onebot": "^4.0.0-beta.2", "@koishijs/plugin-adapter-onebot": "^4.0.0-beta.2",
"@koishijs/plugin-cache-lru": "^1.0.0-alpha.1",
"@types/jest": "^27.0.3", "@types/jest": "^27.0.3",
"@types/lodash": "^4.14.177", "@types/lodash": "^4.14.177",
"@types/node": "^16.11.9", "@types/node": "^16.11.9",
...@@ -33,7 +34,7 @@ ...@@ -33,7 +34,7 @@
"ws": "^8.2.3" "ws": "^8.2.3"
}, },
"peerDependencies": { "peerDependencies": {
"koishi": "^4.0.0-beta.4" "koishi": "^4.0.0-beta.5"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
...@@ -1048,6 +1049,18 @@ ...@@ -1048,6 +1049,18 @@
"koishi": "^4.0.0-beta.2" "koishi": "^4.0.0-beta.2"
} }
}, },
"node_modules/@koishijs/plugin-cache-lru": {
"version": "1.0.0-alpha.1",
"resolved": "https://registry.npmjs.org/@koishijs/plugin-cache-lru/-/plugin-cache-lru-1.0.0-alpha.1.tgz",
"integrity": "sha512-GaLkOMMOy7djNSOT/eGHSUEu4kikmUjmxJIvOrAA/Y7oJAdXaTcY4gcZi5Vtie6NWXUIBssqqJmcJBgF/Bwwvw==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"peerDependencies": {
"koishi": "^4.0.0-alpha.10"
}
},
"node_modules/@koishijs/utils": { "node_modules/@koishijs/utils": {
"version": "5.0.0-beta.1", "version": "5.0.0-beta.1",
"resolved": "https://registry.npmjs.org/@koishijs/utils/-/utils-5.0.0-beta.1.tgz", "resolved": "https://registry.npmjs.org/@koishijs/utils/-/utils-5.0.0-beta.1.tgz",
...@@ -7303,6 +7316,15 @@ ...@@ -7303,6 +7316,15 @@
"ws": "^8.2.1" "ws": "^8.2.1"
} }
}, },
"@koishijs/plugin-cache-lru": {
"version": "1.0.0-alpha.1",
"resolved": "https://registry.npmjs.org/@koishijs/plugin-cache-lru/-/plugin-cache-lru-1.0.0-alpha.1.tgz",
"integrity": "sha512-GaLkOMMOy7djNSOT/eGHSUEu4kikmUjmxJIvOrAA/Y7oJAdXaTcY4gcZi5Vtie6NWXUIBssqqJmcJBgF/Bwwvw==",
"dev": true,
"requires": {
"lru-cache": "^6.0.0"
}
},
"@koishijs/utils": { "@koishijs/utils": {
"version": "5.0.0-beta.1", "version": "5.0.0-beta.1",
"resolved": "https://registry.npmjs.org/@koishijs/utils/-/utils-5.0.0-beta.1.tgz", "resolved": "https://registry.npmjs.org/@koishijs/utils/-/utils-5.0.0-beta.1.tgz",
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@koishijs/plugin-adapter-onebot": "^4.0.0-beta.2", "@koishijs/plugin-adapter-onebot": "^4.0.0-beta.2",
"@koishijs/plugin-cache-lru": "^1.0.0-alpha.1",
"@types/jest": "^27.0.3", "@types/jest": "^27.0.3",
"@types/lodash": "^4.14.177", "@types/lodash": "^4.14.177",
"@types/node": "^16.11.9", "@types/node": "^16.11.9",
......
import { Argv, Command, Context, Logger, Schema, User } from 'koishi'; import {
Argv,
Awaitable,
Command,
Context,
Logger,
Schema,
User,
} from 'koishi';
import { import {
CommandPutConfig, CommandPutConfig,
DoRegisterConfig, DoRegisterConfig,
...@@ -180,18 +188,34 @@ export function KoishiPlugin<T = any>( ...@@ -180,18 +188,34 @@ export function KoishiPlugin<T = any>(
} }
} }
async _applyInnerPlugin( _applyInnerPluginDesc(
baseContext: Context, baseContext: Context,
methodKey: keyof C & string, methodKey: keyof C & string,
pluginDesc: KoishiModulePlugin<any>,
) { ) {
const pluginDesc: KoishiModulePlugin<any> = await this[methodKey](); const pluginCtx = applySelector(baseContext, pluginDesc);
if (!pluginDesc || !pluginDesc.plugin) { if (!pluginDesc || !pluginDesc.plugin) {
throw new Error(`Invalid plugin from method ${methodKey}.`); throw new Error(`Invalid plugin from method ${methodKey}.`);
} }
const pluginCtx = applySelector(baseContext, pluginDesc);
pluginCtx.plugin(pluginDesc.plugin, pluginDesc.options); pluginCtx.plugin(pluginDesc.plugin, pluginDesc.options);
} }
_applyInnerPlugin(baseContext: Context, methodKey: keyof C & string) {
const pluginDescMayBeProm: Awaitable<KoishiModulePlugin<any>> =
this[methodKey]();
if (pluginDescMayBeProm instanceof Promise) {
pluginDescMayBeProm.then((pluginDesc) => {
this._applyInnerPluginDesc(baseContext, methodKey, pluginDesc);
});
} else {
this._applyInnerPluginDesc(
baseContext,
methodKey,
pluginDescMayBeProm,
);
}
}
_registerDeclarationsFor(methodKey: keyof C & string) { _registerDeclarationsFor(methodKey: keyof C & string) {
// console.log(`Handling declaration for ${methodKey}`); // console.log(`Handling declaration for ${methodKey}`);
const regData = reflector.get(KoishiDoRegister, this, methodKey); const regData = reflector.get(KoishiDoRegister, this, methodKey);
...@@ -215,7 +239,7 @@ export function KoishiPlugin<T = any>( ...@@ -215,7 +239,7 @@ export function KoishiPlugin<T = any>(
case 'onevent': case 'onevent':
const { data: eventData } = regData as DoRegisterConfig<'onevent'>; const { data: eventData } = regData as DoRegisterConfig<'onevent'>;
const eventName = eventData.name; const eventName = eventData.name;
baseContext.on(eventData.name, (...args: any[]) => baseContext.on(eventName, (...args: any[]) =>
this[methodKey](...args), this[methodKey](...args),
); );
// special events // special events
...@@ -227,13 +251,7 @@ export function KoishiPlugin<T = any>( ...@@ -227,13 +251,7 @@ export function KoishiPlugin<T = any>(
}*/ }*/
break; break;
case 'plugin': case 'plugin':
this._applyInnerPlugin(baseContext, methodKey) this._applyInnerPlugin(baseContext, methodKey);
.then()
.catch((e) =>
new Logger(originalClass.name).error(
`Failed to load plugin from method ${methodKey}: ${e.toString()}`,
),
);
break; break;
case 'command': case 'command':
const { data: commandData } = const { data: commandData } =
......
import { App, Context } from 'koishi'; import { App, Context } from 'koishi';
import { InjectContext, OnApply, OnConnect, OnDisconnect, Provide } from '..'; import {
import { KoishiPlugin } from '../src/register'; KoishiPlugin,
OnApply,
OnConnect,
OnDisconnect,
} from '../src/register';
import { Inject, InjectContext, Provide } from '../src/decorators';
declare module 'koishi' { declare module 'koishi' {
// eslint-disable-next-line @typescript-eslint/no-namespace // eslint-disable-next-line @typescript-eslint/no-namespace
namespace Context { namespace Context {
interface Services { interface Services {
myPlugin: MyPlugin; immediateDependency: ImmediateDependency;
nonImmediateDependency: NonImmediateDependency;
myPlugin: TestingBase;
} }
} }
} }
@Provide('immediateDependency', { immediate: true })
@KoishiPlugin()
class ImmediateDependency {}
@Provide('nonImmediateDependency')
@KoishiPlugin()
class NonImmediateDependency {}
@Provide('myPlugin', { immediate: true }) @Provide('myPlugin', { immediate: true })
@KoishiPlugin() @KoishiPlugin()
class MyPlugin implements OnApply, OnConnect, OnDisconnect { class TestingBase implements OnConnect, OnDisconnect, OnApply {
@InjectContext() @InjectContext()
ctx: Context; ctx: Context;
applied = false;
connected = false;
disconnected = false;
onApply() { onApply() {
this.applied = true; this.applied = true;
} }
onConnect() { onConnect() {
this.connected = true; this.connected = true;
} }
onDisconnect() { onDisconnect() {
this.disconnected = true; this.disconnected = true;
} }
applied = false;
connected = false;
disconnected = false;
}
class MyPlugin extends TestingBase {}
class MyPlugin2 extends TestingBase {
@Inject(true)
immediateDependency: ImmediateDependency;
}
class MyPlugin3 extends TestingBase {
@Inject(true)
nonImmediateDependency: NonImmediateDependency;
} }
describe('Apply and Connect', () => { async function RunApplyTest(app: App) {
await app.start();
const myPlugin = app.myPlugin;
expect(myPlugin.applied).toBe(true);
expect(myPlugin.connected).toBe(true);
expect(myPlugin.disconnected).toBe(false);
await myPlugin.ctx.dispose();
expect(myPlugin.disconnected).toBe(true);
expect(app.immediateDependency).toBeDefined();
expect(app.nonImmediateDependency).toBeDefined();
await app.stop();
}
describe('Apply and Connect in koishi-thirdeye', () => {
let app: App;
beforeEach(() => {
app = new App();
app.plugin(ImmediateDependency);
app.plugin(NonImmediateDependency);
});
it('should be applied and connected', async () => { it('should be applied and connected', async () => {
const app = new App();
app.plugin(MyPlugin); app.plugin(MyPlugin);
const myPlugin = app.myPlugin; const myPlugin = app.myPlugin;
expect(myPlugin.applied).toBe(true); expect(myPlugin.applied).toBe(true);
expect(myPlugin.connected).toBe(false); expect(myPlugin.connected).toBe(false);
expect(myPlugin.disconnected).toBe(false); expect(myPlugin.disconnected).toBe(false);
await app.start(); await RunApplyTest(app);
expect(myPlugin.connected).toBe(true); });
expect(myPlugin.disconnected).toBe(false); it('should be applied and connected with immediate dependency', async () => {
await myPlugin.ctx.dispose(); app.plugin(MyPlugin2);
expect(myPlugin.disconnected).toBe(true); await RunApplyTest(app);
await app.stop();
}); });
/*it('should be applied and connected with non-immediate dependency', async () => {
app.plugin(MyPlugin3);
await RunApplyTest(app);
});*/
}); });
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