Files
deepseek-harness/vendor/loader/src/config/group.ts
T
Tianyi Cui 07f4047ff0 Use explicit ts specifiers for declarations
Restore explicit .ts relative specifiers in source and enable rewriteRelativeImportExtensions so emitted JS uses .js while declarations keep explicit .ts specifiers. Add a NodeNext declaration-consumer gate to prevent extensionless declaration regressions.
2026-06-22 06:11:00 +08:00

91 lines
2.5 KiB
TypeScript

import { Context, Service } from 'cordis'
import { Entry, EntryOptions } from './entry.ts'
import { EntryTree } from './tree.ts'
/** Runtime owner for a list of child loader entries. */
export class EntryGroup {
static readonly key = Symbol.for('cordis.group')
public data: EntryOptions[] = []
constructor(public ctx: Context, public tree: EntryTree) {
const entry = ctx.fiber.entry
if (entry) entry.subgroup = this
}
get context(): Context {
return this.ctx
}
async create(options: Omit<EntryOptions, 'id'>) {
const id = this.tree.ensureId(options)
const entry: Entry = this.tree.store[id] ??= new Entry(this.ctx.loader)
// Entry may be moved from another group,
// so we need to update the parent reference.
entry.parent = this
// Use `create: true` to replace existing entry.options.
await entry.update(options, true, true)
return entry.id
}
unlink(options: EntryOptions) {
const config = this.data
const index = config.indexOf(options)
if (index >= 0) config.splice(index, 1)
}
remove(id: string, isDispose = false) {
const entry = this.tree.store[id]
if (!entry) return
entry.fiber?.dispose()
if (!isDispose) {
this.unlink(entry.options)
}
delete this.tree.store[id]
this.context.emit('loader/partial-dispose', entry, entry.options, false)
}
async update(config: EntryOptions[]) {
const oldConfig = this.data as EntryOptions[]
this.data = config
const oldMap = Object.fromEntries(oldConfig.map(options => [options.id, options]))
const newMap = Object.fromEntries(config.map(options => [options.id ?? Symbol('anonymous'), options]))
// update inner plugins
const ids = Reflect.ownKeys({ ...oldMap, ...newMap }) as string[]
await Promise.all(ids.map(async (id) => {
if (newMap[id]) {
await this.create(newMap[id]).catch((error) => {
this.ctx.logger.error(error)
})
} else {
this.remove(id)
}
}))
}
stop() {
for (const options of this.data) {
this.remove(options.id, true)
}
}
}
/** Plugin that mounts a nested loader entry group. */
export class Group extends EntryGroup {
static initial: Omit<EntryOptions, 'id'>[] = []
static readonly [EntryGroup.key] = true
constructor(public ctx: Context, public config: EntryOptions[]) {
super(ctx, ctx.fiber.entry!.parent.tree)
ctx.on('internal/update', (config) => {
this.update(config)
})
}
async* [Service.init]() {
yield () => this.stop()
await this.update(this.config)
}
}