From d3775640270b07a4fb0d0ecbc46c7fbee103c0e7 Mon Sep 17 00:00:00 2001 From: Shigma Date: Tue, 4 Jun 2024 01:38:59 +0800 Subject: [PATCH] feat(loader): support generics for loader --- packages/core/src/context.ts | 4 ++-- packages/loader/src/entry.ts | 29 ++++++++++++++++------------- packages/loader/src/file.ts | 6 +++--- packages/loader/src/loader.ts | 2 +- packages/loader/src/tree.ts | 12 ++++++++---- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/packages/core/src/context.ts b/packages/core/src/context.ts index fa43365..9de0b29 100644 --- a/packages/core/src/context.ts +++ b/packages/core/src/context.ts @@ -105,7 +105,7 @@ export class Context { if (!ctx.runtime.plugin) return // Case 5: custom inject checks if (ctx.bail('internal/inject', name)) return - ctx.emit('internal/warning', new Error(`property ${name} is not registered, declare it as \`inject\` to suppress this warning`)) + ctx.emit(ctx, 'internal/warning', new Error(`property ${name} is not registered, declare it as \`inject\` to suppress this warning`)) } const [name, internal] = Context.resolveInject(ctx, prop) @@ -236,7 +236,7 @@ export class Context { }) } if (isUnproxyable(value)) { - ctx.emit('internal/warning', new Error(`service ${name} is an unproxyable object, which may lead to unexpected behavior`)) + ctx.emit(ctx, 'internal/warning', new Error(`service ${name} is an unproxyable object, which may lead to unexpected behavior`)) } // setup filter for events diff --git a/packages/loader/src/entry.ts b/packages/loader/src/entry.ts index 346b022..9014550 100644 --- a/packages/loader/src/entry.ts +++ b/packages/loader/src/entry.ts @@ -31,20 +31,24 @@ function sortKeys(object: T, prepend = ['id', 'name'], append = [' return Object.assign(object, Object.fromEntries([...part1, ...rest, ...part2])) } -export class Entry { +export class Entry { static readonly key = Symbol.for('cordis.entry') - public ctx: Context - public fork?: ForkScope + public ctx: C + public fork?: ForkScope public suspend = false public parent!: EntryGroup public options!: EntryOptions public subgroup?: EntryGroup - public subtree?: EntryTree + public subtree?: EntryTree - constructor(public loader: Loader) { + constructor(public loader: Loader) { this.ctx = loader.ctx.extend() - this.ctx.emit('loader/entry-init', this) + this.context.emit('loader/entry-init', this) + } + + get context(): Context { + return this.ctx } get id() { @@ -74,7 +78,7 @@ export class Entry { patch(options: Partial = {}) { // step 1: prepare isolate map const meta = {} as EntryUpdateMeta - this.ctx.emit(meta, 'loader/before-patch', this) + this.context.emit(meta, 'loader/before-patch', this) // step 1: set prototype for transferred context Object.setPrototypeOf(this.ctx, this.parent.ctx) @@ -93,8 +97,7 @@ export class Entry { } } - this.ctx.emit(meta, 'loader/after-patch', this) - return this.ctx + this.context.emit(meta, 'loader/after-patch', this) } async refresh() { @@ -127,7 +130,7 @@ export class Entry { if (!this._check()) { await this.stop() } else if (this.fork) { - this.parent.ctx.emit('loader/partial-dispose', this, legacy, true) + this.context.emit('loader/partial-dispose', this, legacy, true) this.patch(options) } else { await this.start() @@ -136,15 +139,15 @@ export class Entry { async start() { const exports = await this.parent.tree.import(this.options.name).catch((error: any) => { - this.parent.ctx.emit('internal/error', new Error(`Cannot find package "${this.options.name}"`)) - this.parent.ctx.emit('internal/error', error) + this.context.emit('internal/error', new Error(`Cannot find package "${this.options.name}"`)) + this.context.emit('internal/error', error) }) if (!exports) return const plugin = this.loader.unwrapExports(exports) this.patch() this.ctx[Entry.key] = this this.fork = this.ctx.plugin(plugin, this.options.config) - this.ctx.emit('loader/entry-fork', this, 'apply') + this.context.emit('loader/entry-fork', this, 'apply') } async stop() { diff --git a/packages/loader/src/file.ts b/packages/loader/src/file.ts index cb00df6..c85c249 100644 --- a/packages/loader/src/file.ts +++ b/packages/loader/src/file.ts @@ -96,12 +96,12 @@ export namespace LoaderFile { } } -export class ImportTree extends EntryTree { +export class ImportTree extends EntryTree { static reusable = true protected file!: LoaderFile - constructor(public ctx: Context) { + constructor(public ctx: C) { super(ctx) ctx.on('ready', () => this.start()) ctx.on('dispose', () => this.stop()) @@ -122,7 +122,7 @@ export class ImportTree extends EntryTree { } write() { - this.ctx.emit('loader/config-update') + this.context.emit('loader/config-update') return this.file.write(this.root.data) } diff --git a/packages/loader/src/loader.ts b/packages/loader/src/loader.ts index 732d350..32242b0 100644 --- a/packages/loader/src/loader.ts +++ b/packages/loader/src/loader.ts @@ -47,7 +47,7 @@ export namespace Loader { } } -export abstract class Loader extends ImportTree { +export abstract class Loader extends ImportTree { // TODO auto inject optional when provided? static inject = { optional: ['loader'], diff --git a/packages/loader/src/tree.ts b/packages/loader/src/tree.ts index c3cc1d7..834da03 100644 --- a/packages/loader/src/tree.ts +++ b/packages/loader/src/tree.ts @@ -3,21 +3,25 @@ import { Dict } from 'cosmokit' import { Entry, EntryOptions } from './entry.ts' import { EntryGroup } from './group.ts' -export abstract class EntryTree { +export abstract class EntryTree { static readonly sep = ':' static readonly [EntryGroup.key] = true public url!: string public root: EntryGroup - public store: Dict = Object.create(null) + public store: Dict> = Object.create(null) - constructor(public ctx: Context) { + constructor(public ctx: C) { this.root = new EntryGroup(ctx, this) const entry = ctx.scope.entry if (entry) entry.subtree = this } - * entries(): Generator { + get context(): Context { + return this.ctx + } + + * entries(): Generator, void, void> { for (const entry of Object.values(this.store)) { yield entry if (!entry.subtree) continue