Skip to content

Commit

Permalink
feat(core): support Context.extend, drop standalone service
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Feb 17, 2024
1 parent 1ea5ddc commit 64f19b9
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 24 deletions.
10 changes: 5 additions & 5 deletions packages/core/src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export interface Context {

export class Context {
static readonly invoke = Symbol.for('cordis.invoke')
static readonly config = Symbol.for('cordis.config')
static readonly extend = Symbol.for('cordis.extend')
static readonly events = Symbol.for('cordis.events')
static readonly static = Symbol.for('cordis.static')
static readonly filter = Symbol.for('cordis.filter')
Expand All @@ -66,20 +66,20 @@ export class Context {
static readonly internal = Symbol.for('cordis.internal')
static readonly intercept = Symbol.for('cordis.intercept')

static createProxy(ctx: any, value: any) {
static createTraceable(ctx: any, value: any) {
const proxy = new Proxy(value, {
get: (target, name, receiver) => {
if (name === Context.current || name === 'caller') return ctx
return Reflect.get(target, name, receiver)
},
apply: (target, thisArg, args) => {
return Context.applyProxy(proxy, target, thisArg, args)
return Context.applyTraceable(proxy, target, thisArg, args)
},
})
return proxy
}

static applyProxy(proxy: any, value: any, thisArg: any, args: any[]) {
static applyTraceable(proxy: any, value: any, thisArg: any, args: any[]) {
if (!value[Context.invoke]) return Reflect.apply(value, thisArg, args)
return value[Context.invoke].apply(proxy, args)
}
Expand Down Expand Up @@ -274,7 +274,7 @@ export class Context {
defineProperty(value, Context.current, this)
return value
}
return Context.createProxy(this, value)
return Context.createTraceable(this, value)
}

provide(name: string, value?: any, builtin?: boolean) {
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ export class MainScope<C extends Context = Context> extends EffectScope<C> {
super(registry[Context.current] as C, config)
registry.set(plugin, this)
if (!plugin) {
this.name = 'app'
this.name = 'root'
this.isActive = true
} else {
this.setup()
Expand Down
46 changes: 31 additions & 15 deletions packages/core/src/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,28 @@ export namespace Service {
export interface Options {
name?: string
immediate?: boolean
standalone?: boolean
}
}

function makeFunctional(proto: {}) {
function makeCallableProto(proto: {}) {
if (proto === Object.prototype) return Function.prototype
const result = Object.create(makeFunctional(Object.getPrototypeOf(proto)))
const result = Object.create(makeCallableProto(Object.getPrototypeOf(proto)))
for (const key of Reflect.ownKeys(proto)) {
Object.defineProperty(result, key, Object.getOwnPropertyDescriptor(proto, key)!)
}
return result
}

export abstract class Service<C extends Context = Context> {
function makeCallable(ctx: Context, name: string, proto: {}) {
const self = function (...args: any[]) {
const proxy = Context.createTraceable(ctx, self)
return Context.applyTraceable(proxy, self, this, args)
}
defineProperty(self, 'name', name)
return Object.setPrototypeOf(self, proto)
}

export abstract class Service<C extends Context = Context, T = unknown> {
static immediate = false
static Context = Context

Expand All @@ -29,24 +37,20 @@ export abstract class Service<C extends Context = Context> {
protected ctx!: C
protected [Context.current]!: C

constructor(ctx: C | undefined, public readonly name: string, options?: boolean | Service.Options) {
constructor(ctx: C | undefined, public readonly name: string, options?: boolean) {
let self = this
if (self[Context.invoke]) {
// functional service
self = function (...args: any[]) {
const proxy = Context.createProxy(ctx, self)
return Context.applyProxy(proxy, self, this, args)
} as any
defineProperty(self, 'name', name)
Object.setPrototypeOf(self, makeFunctional(Object.getPrototypeOf(this)))
// FIXME ctx!
self = makeCallable(ctx!, name, makeCallableProto(Object.getPrototypeOf(this)))
}

self.ctx = ctx ?? new (self.constructor as any).Context()
self.ctx.provide(name)
defineProperty(self, Context.current, ctx)

const resolved = typeof options === 'boolean' ? { immediate: options } : options ?? {}
if (!resolved.standalone && resolved.immediate) {
if (resolved.immediate) {
self.ctx.provide(name)
self.ctx.runtime.name = name
if (ctx) self[Context.expose] = name
else self.ctx[name] = self
}
Expand All @@ -55,7 +59,7 @@ export abstract class Service<C extends Context = Context> {
// await until next tick because derived class has not been initialized yet
await Promise.resolve()
await self.start()
if (!resolved.standalone && !resolved.immediate) self.ctx[name] = self
if (!resolved.immediate) self.ctx[name] = self
})

self.ctx.on('dispose', () => self.stop())
Expand All @@ -66,6 +70,18 @@ export abstract class Service<C extends Context = Context> {
return ctx[Context.shadow][this.name] === this.ctx[Context.shadow][this.name]
}

[Context.extend](props?: any) {
const caller = this[Context.current]
let self: typeof this
if (this[Context.invoke]) {
self = makeCallable(caller, this.name, this)
} else {
self = Object.create(this)
}
defineProperty(self, Context.current, caller)
return Context.associate(Object.assign(self, props), this.name)
}

static [Symbol.hasInstance](instance: any) {
let constructor = instance.constructor
while (constructor) {
Expand Down
8 changes: 5 additions & 3 deletions packages/core/tests/service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,8 +282,8 @@ describe('Service', () => {
}

class Foo extends Service {
constructor(ctx: Context, public config?: Config, standalone?: boolean) {
super(ctx, 'foo', { immediate: true, standalone })
constructor(ctx: Context, public config?: Config) {
super(ctx, 'foo', true)
}

[Context.invoke](init?: Config) {
Expand All @@ -304,7 +304,9 @@ describe('Service', () => {
}

extend(config?: Config) {
return new Foo(this[Context.current], { ...this.config, ...config }, true)
return this[Context.extend]({
config: { ...this.config, ...config },
})
}
}

Expand Down

0 comments on commit 64f19b9

Please sign in to comment.