From 79c564aad1a2eb1d853bd81adbaa11aa2af400fd Mon Sep 17 00:00:00 2001 From: Shigma Date: Sun, 12 May 2024 15:51:24 +0800 Subject: [PATCH] feat(cordis): support inject at entry level --- packages/cordis/src/worker/logger.ts | 2 ++ packages/core/src/context.ts | 2 ++ packages/core/src/registry.ts | 2 +- packages/core/src/scope.ts | 36 ++++++++++++++++++---------- packages/core/src/utils.ts | 3 ++- packages/loader/src/entry.ts | 11 +++++---- 6 files changed, 38 insertions(+), 18 deletions(-) diff --git a/packages/cordis/src/worker/logger.ts b/packages/cordis/src/worker/logger.ts index 1ccc4ad..07af2b8 100644 --- a/packages/cordis/src/worker/logger.ts +++ b/packages/cordis/src/worker/logger.ts @@ -1,4 +1,5 @@ import { Logger } from '@cordisjs/logger' +import { kGroup } from '@cordisjs/loader' import { Context } from '../index.ts' declare module '@cordisjs/loader' { @@ -35,6 +36,7 @@ export function apply(ctx: Context, config: Config = {}) { }) ctx.on('loader/entry', (type, entry) => { + if (entry.fork?.runtime.plugin?.[kGroup]) return ctx.logger('loader').info('%s plugin %c', type, entry.options.name) }) diff --git a/packages/core/src/context.ts b/packages/core/src/context.ts index 0ba4830..92d0bf4 100644 --- a/packages/core/src/context.ts +++ b/packages/core/src/context.ts @@ -55,6 +55,7 @@ export class Context { static readonly static: unique symbol = symbols.static as any static readonly filter: unique symbol = symbols.filter as any static readonly expose: unique symbol = symbols.expose as any + static readonly inject: unique symbol = symbols.inject as any static readonly isolate: unique symbol = symbols.isolate as any static readonly internal: unique symbol = symbols.internal as any static readonly intercept: unique symbol = symbols.intercept as any @@ -163,6 +164,7 @@ export class Context { constructor(config?: any) { const self: Context = new Proxy(this, Context.handler) config = resolveConfig(this.constructor, config) + self[symbols.inject] = {} self[symbols.isolate] = Object.create(null) self[symbols.intercept] = Object.create(null) self.root = self diff --git a/packages/core/src/registry.ts b/packages/core/src/registry.ts index 1aa1a8d..050409c 100644 --- a/packages/core/src/registry.ts +++ b/packages/core/src/registry.ts @@ -1,4 +1,4 @@ -import { Dict, defineProperty } from 'cosmokit' +import { defineProperty, Dict } from 'cosmokit' import { Context } from './context.ts' import { ForkScope, MainScope } from './scope.ts' import { resolveConfig } from './utils.ts' diff --git a/packages/core/src/scope.ts b/packages/core/src/scope.ts index 96d9c73..a3b7cb1 100644 --- a/packages/core/src/scope.ts +++ b/packages/core/src/scope.ts @@ -1,6 +1,6 @@ import { deepEqual, defineProperty, isNullable, remove } from 'cosmokit' import { Context } from './context.ts' -import { Plugin, Registry } from './registry.ts' +import { Inject, Plugin, Registry } from './registry.ts' import { isConstructor, resolveConfig } from './utils.ts' declare module './context.ts' { @@ -77,6 +77,7 @@ export abstract class EffectScope { constructor(public parent: C, public config: C['config']) { this.uid = parent.registry ? parent.registry.counter : 0 this.ctx = this.context = parent.extend({ scope: this }) + this.ctx[Context.inject] = {} this.proxy = new Proxy({}, { get: (target, key) => Reflect.get(this.config, key), }) @@ -166,7 +167,7 @@ export abstract class EffectScope { this.reset() } - protected setupInject() { + protected setupInjectHooks() { if (!this.runtime.using.length) return defineProperty(this.context.on('internal/before-service', (name) => { if (!this.runtime.using.includes(name)) return @@ -286,7 +287,7 @@ export class ForkScope extends EffectScope { this.context.emit('internal/fork', this) if (runtime.isReusable) { // non-reusable plugin forks are not responsive to isolated service changes - this.setupInject() + this.setupInjectHooks() } this.init(error) @@ -355,18 +356,29 @@ export class MainScope extends EffectScope { return true } + private setInject(inject?: string[] | Inject): void { + if (Array.isArray(inject)) { + for (const name of inject) { + this.using.push(name) + this.inject.add(name) + } + } else if (inject) { + for (const name of inject.required || []) { + this.using.push(name) + this.inject.add(name) + } + for (const name of inject.optional || []) { + this.inject.add(name) + } + } + } + private setup() { const { name } = this.plugin if (name && name !== 'apply') this.name = name this.schema = this.plugin['Config'] || this.plugin['schema'] - const inject = this.plugin['using'] || this.plugin['inject'] || [] - if (Array.isArray(inject)) { - this.using = inject - this.inject = new Set(inject) - } else { - this.using = inject.required || [] - this.inject = new Set([...this.using, ...inject.optional || []]) - } + this.setInject(this.plugin['using'] || this.plugin['inject']) + this.setInject(this.parent[Context.inject]) this.isReusable = this.plugin['reusable'] this.isReactive = this.plugin['reactive'] this.context.emit('internal/runtime', this) @@ -374,7 +386,7 @@ export class MainScope extends EffectScope { if (this.isReusable) { this.forkables.push(this.apply) } else { - super.setupInject() + super.setupInjectHooks() } } diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 6d00898..7c8c668 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -8,6 +8,7 @@ export const symbols = { static: Symbol.for('cordis.static') as typeof Context.static, filter: Symbol.for('cordis.filter') as typeof Context.filter, expose: Symbol.for('cordis.expose') as typeof Context.expose, + inject: Symbol.for('cordis.inject') as typeof Context.inject, isolate: Symbol.for('cordis.isolate') as typeof Context.isolate, internal: Symbol.for('cordis.internal') as typeof Context.internal, intercept: Symbol.for('cordis.intercept') as typeof Context.intercept, @@ -56,7 +57,7 @@ export function joinPrototype(proto1: {}, proto2: {}) { export function createTraceable(ctx: any, value: any) { const proxy = new Proxy(value, { get: (target, name, receiver) => { - if (name === symbols.origin || name === 'caller') return ctx + if (name === symbols.origin) return ctx return Reflect.get(target, name, receiver) }, apply: (target, thisArg, args) => { diff --git a/packages/loader/src/entry.ts b/packages/loader/src/entry.ts index cee1221..8a4c988 100644 --- a/packages/loader/src/entry.ts +++ b/packages/loader/src/entry.ts @@ -1,4 +1,4 @@ -import { Context, ForkScope } from '@cordisjs/core' +import { Context, ForkScope, Inject } from '@cordisjs/core' import { Dict } from 'cosmokit' import Loader from './shared.ts' @@ -10,6 +10,7 @@ export namespace Entry { disabled?: boolean | null intercept?: Dict | null isolate?: Dict | null + inject?: string[] | Inject | null when?: any } } @@ -63,6 +64,8 @@ export class Entry { } patch(ctx: Context, ref: Context = ctx) { + ctx[Context.inject] = this.options.inject + // part 1: prepare isolate map const newMap: Dict = Object.create(Object.getPrototypeOf(ref[Context.isolate])) for (const [key, label] of Object.entries(this.options.isolate ?? {})) { @@ -103,10 +106,10 @@ export class Entry { // part 3.2: update service impl if (ctx === ref) { - // prevent double update - this.fork?.update(this.options.config) swap(ctx[Context.isolate], newMap) swap(ctx[Context.intercept], this.options.intercept) + // prevent double update + this.fork?.update(this.options.config) } else { // handle entry transfer Object.setPrototypeOf(ctx, Object.getPrototypeOf(ref)) @@ -159,13 +162,13 @@ export class Entry { } this.patch(this.fork.parent) } else { - this.parent.emit('loader/entry', 'apply', this) const plugin = await this.loader.resolve(this.options.name) if (!plugin) return const ctx = this.createContext() this.patch(ctx) this.fork = ctx.plugin(plugin, this.options.config) this.fork.entry = this + this.parent.emit('loader/entry', 'apply', this) } }