Skip to content

Commit

Permalink
feat(cordis): support inject at entry level
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed May 12, 2024
1 parent 177ea0d commit 79c564a
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 18 deletions.
2 changes: 2 additions & 0 deletions packages/cordis/src/worker/logger.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Logger } from '@cordisjs/logger'
import { kGroup } from '@cordisjs/loader'
import { Context } from '../index.ts'

declare module '@cordisjs/loader' {
Expand Down Expand Up @@ -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)
})

Expand Down
2 changes: 2 additions & 0 deletions packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/registry.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
36 changes: 24 additions & 12 deletions packages/core/src/scope.ts
Original file line number Diff line number Diff line change
@@ -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' {
Expand Down Expand Up @@ -77,6 +77,7 @@ export abstract class EffectScope<C extends Context = Context> {
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),
})
Expand Down Expand Up @@ -166,7 +167,7 @@ export abstract class EffectScope<C extends Context = Context> {
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
Expand Down Expand Up @@ -286,7 +287,7 @@ export class ForkScope<C extends Context = Context> extends EffectScope<C> {
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)
Expand Down Expand Up @@ -355,26 +356,37 @@ export class MainScope<C extends Context = Context> extends EffectScope<C> {
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)

if (this.isReusable) {
this.forkables.push(this.apply)
} else {
super.setupInject()
super.setupInjectHooks()
}
}

Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) => {
Expand Down
11 changes: 7 additions & 4 deletions packages/loader/src/entry.ts
Original file line number Diff line number Diff line change
@@ -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'

Expand All @@ -10,6 +10,7 @@ export namespace Entry {
disabled?: boolean | null
intercept?: Dict | null
isolate?: Dict<true | string> | null
inject?: string[] | Inject | null
when?: any
}
}
Expand Down Expand Up @@ -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<symbol> = Object.create(Object.getPrototypeOf(ref[Context.isolate]))
for (const [key, label] of Object.entries(this.options.isolate ?? {})) {
Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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)
}
}

Expand Down

0 comments on commit 79c564a

Please sign in to comment.