From 78837b3e568eecf811c8b446ec3afe9361dbf89a Mon Sep 17 00:00:00 2001 From: Shigma Date: Fri, 16 Aug 2024 00:14:41 +0800 Subject: [PATCH] feat(cordis): implement context store --- packages/core/src/context.ts | 13 ++++++++++--- packages/core/src/reflect.ts | 20 ++++++++------------ packages/core/src/utils.ts | 2 +- packages/loader/src/config/isolate.ts | 17 ++++++++--------- 4 files changed, 27 insertions(+), 25 deletions(-) diff --git a/packages/core/src/context.ts b/packages/core/src/context.ts index eb629af..069f79a 100644 --- a/packages/core/src/context.ts +++ b/packages/core/src/context.ts @@ -16,6 +16,11 @@ export namespace Context { prototype?: {} } + export interface Item { + value?: any + source: C + } + export type Internal = Internal.Service | Internal.Accessor | Internal.Alias export namespace Internal { @@ -43,6 +48,7 @@ export namespace Context { export interface Intercept {} export interface Context { + [Context.store]: Dict, symbol> [Context.isolate]: Dict [Context.intercept]: Intercept [Context.internal]: Dict @@ -54,7 +60,7 @@ export interface Context { } export class Context { - static readonly source: unique symbol = symbols.source as any + static readonly store: unique symbol = symbols.store as any static readonly events: unique symbol = symbols.events as any static readonly static: unique symbol = symbols.static as any static readonly filter: unique symbol = symbols.filter as any @@ -81,8 +87,9 @@ export class Context { constructor(config?: any) { config = resolveConfig(this.constructor, config) - this[symbols.internal] = Object.create(null) + this[symbols.store] = Object.create(null) this[symbols.isolate] = Object.create(null) + this[symbols.internal] = Object.create(null) this[symbols.intercept] = Object.create(null) const self: Context = new Proxy(this, ReflectService.handler) self.root = self @@ -128,7 +135,7 @@ export class Context { extend(meta = {}): this { const source = Reflect.getOwnPropertyDescriptor(this, symbols.shadow)?.value const self = Object.assign(Object.create(getTraceable(this, this)), meta) - if (!source || Object.hasOwn(meta, symbols.source)) return self + if (!source) return self return Object.assign(Object.create(self), { [symbols.shadow]: source }) } diff --git a/packages/core/src/reflect.ts b/packages/core/src/reflect.ts index 67b8f91..a3c3a58 100644 --- a/packages/core/src/reflect.ts +++ b/packages/core/src/reflect.ts @@ -108,14 +108,15 @@ class ReflectService { get(name: string) { const internal = this.ctx[symbols.internal][name] if (internal?.type !== 'service') return - const value = this.ctx.root[this.ctx[symbols.isolate][name]] + const key = this.ctx[symbols.isolate][name] + const value = this.ctx[symbols.store][key]?.value return getTraceable(this.ctx, value) } set(name: string, value: any) { this.provide(name) const key = this.ctx[symbols.isolate][name] - const oldValue = this.ctx.root[key] + const oldValue = this.ctx[symbols.store][key]?.value value ??= undefined let dispose = () => {} if (oldValue === value) return dispose @@ -141,13 +142,7 @@ class ReflectService { } ctx.emit(self, 'internal/before-service', name, value) - ctx.root[key] = value - if (isObject(value)) { - try { - // Frozen objects cannot be modified - defineProperty(value, symbols.source, ctx) - } catch {} - } + ctx[symbols.store][key] = { value, source: ctx } ctx.emit(self, 'internal/service', name, oldValue) return dispose } @@ -157,9 +152,10 @@ class ReflectService { if (name in internal) return const key = Symbol(name) internal[name] = { type: 'service', builtin } - this.ctx.root[key] = value this.ctx.root[symbols.isolate][name] = key - isObject(value) && defineProperty(value, symbols.tracker, { + if (!isObject(value)) return + this.ctx[symbols.store][key] = { value, source: null! } + defineProperty(value, symbols.tracker, { associate: name, property: 'ctx', }) @@ -172,7 +168,7 @@ class ReflectService { return () => delete this.ctx.root[symbols.isolate][name] } - accessor(name: string, options: Omit, leak = false) { + accessor(name: string, options: Omit) { this.ctx.scope.effect(() => { return this._accessor(name, options) }) diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 8d25149..3ede1f8 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -13,7 +13,7 @@ export const symbols = { original: Symbol.for('cordis.original'), // context symbols - source: Symbol.for('cordis.source') as typeof Context.source, + store: Symbol.for('cordis.store') as typeof Context.store, events: Symbol.for('cordis.events') as typeof Context.events, static: Symbol.for('cordis.static') as typeof Context.static, filter: Symbol.for('cordis.filter') as typeof Context.filter, diff --git a/packages/loader/src/config/isolate.ts b/packages/loader/src/config/isolate.ts index 22cf90c..e06116c 100644 --- a/packages/loader/src/config/isolate.ts +++ b/packages/loader/src/config/isolate.ts @@ -110,15 +110,14 @@ export function apply(ctx: Context) { const delim = entry.loader.delims[key] ??= Symbol(`delim:${key}`) entry.ctx[delim] = Symbol(`${key}#${entry.id}`) for (const symbol of [oldMap[key], this.newMap[key]]) { - const value = symbol && entry.ctx[symbol] - if (!(value instanceof Object)) continue - const source = Reflect.getOwnPropertyDescriptor(value, Context.source)?.value - if (!source) { + const item = symbol && entry.ctx[Context.store][symbol] + if (!item) continue + if (!item.source) { entry.ctx.emit(entry.ctx, 'internal/warning', new Error(`expected service ${key} to be implemented`)) continue } - this.diff.push([key, oldMap[key], this.newMap[key], entry.ctx[delim], source[delim]]) - if (entry.ctx[delim] !== source[delim]) break + this.diff.push([key, oldMap[key], this.newMap[key], entry.ctx[delim], item.source[delim]]) + if (entry.ctx[delim] !== item.source[delim]) break } } @@ -142,9 +141,9 @@ export function apply(ctx: Context) { ctx.on('loader/after-patch', function (entry) { // step 5: replace service impl for (const [, symbol1, symbol2, flag1, flag2] of this.diff) { - if (flag1 === flag2 && entry.ctx[symbol1] && !entry.ctx[symbol2]) { - entry.ctx.root[symbol2] = entry.ctx.root[symbol1] - delete entry.ctx.root[symbol1] + if (flag1 === flag2 && entry.ctx[Context.store][symbol1] && !entry.ctx[Context.store][symbol2]) { + entry.ctx[Context.store][symbol2] = entry.ctx[Context.store][symbol1] + delete entry.ctx[Context.store][symbol1] } }