Skip to content

Commit

Permalink
feat(loader): support generics for loader
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jun 3, 2024
1 parent 8601195 commit d377564
Show file tree
Hide file tree
Showing 5 changed files with 30 additions and 23 deletions.
4 changes: 2 additions & 2 deletions packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
29 changes: 16 additions & 13 deletions packages/loader/src/entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,24 @@ function sortKeys<T extends {}>(object: T, prepend = ['id', 'name'], append = ['
return Object.assign(object, Object.fromEntries([...part1, ...rest, ...part2]))
}

export class Entry {
export class Entry<C extends Context = Context> {
static readonly key = Symbol.for('cordis.entry')

public ctx: Context
public fork?: ForkScope
public ctx: C
public fork?: ForkScope<C>
public suspend = false
public parent!: EntryGroup
public options!: EntryOptions
public subgroup?: EntryGroup
public subtree?: EntryTree
public subtree?: EntryTree<C>

constructor(public loader: Loader) {
constructor(public loader: Loader<C>) {
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() {
Expand Down Expand Up @@ -74,7 +78,7 @@ export class Entry {
patch(options: Partial<EntryOptions> = {}) {
// 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)
Expand All @@ -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() {
Expand Down Expand Up @@ -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()
Expand All @@ -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() {
Expand Down
6 changes: 3 additions & 3 deletions packages/loader/src/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,12 @@ export namespace LoaderFile {
}
}

export class ImportTree extends EntryTree {
export class ImportTree<C extends Context = Context> extends EntryTree<C> {
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())
Expand All @@ -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)
}

Expand Down
2 changes: 1 addition & 1 deletion packages/loader/src/loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export namespace Loader {
}
}

export abstract class Loader<C extends Context = Context> extends ImportTree {
export abstract class Loader<C extends Context = Context> extends ImportTree<C> {
// TODO auto inject optional when provided?
static inject = {
optional: ['loader'],
Expand Down
12 changes: 8 additions & 4 deletions packages/loader/src/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<C extends Context = Context> {
static readonly sep = ':'
static readonly [EntryGroup.key] = true

public url!: string
public root: EntryGroup
public store: Dict<Entry> = Object.create(null)
public store: Dict<Entry<C>> = 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<Entry, void, void> {
get context(): Context {
return this.ctx
}

* entries(): Generator<Entry<C>, void, void> {
for (const entry of Object.values(this.store)) {
yield entry
if (!entry.subtree) continue
Expand Down

0 comments on commit d377564

Please sign in to comment.