Skip to content

Commit

Permalink
feat: support ctx.localize()
Browse files Browse the repository at this point in the history
  • Loading branch information
shigma committed Jun 15, 2022
1 parent 20212d8 commit b78516f
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 8 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"chai": "^4.3.6",
"chai-as-promised": "^7.1.1",
"chai-shape": "^1.0.0",
"dtsc": "^1.1.0",
"dtsc": "^1.1.1",
"esbuild": "^0.14.39",
"esbuild-register": "^3.3.2",
"jest-mock": "^28.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class App extends Context {
counter = 0

constructor(config?: App.Config) {
super({ filter: () => true } as any)
super({ filter: () => true, mapping: Object.create(null) } as any)
this.app = this
this.options = Registry.validate(App, config)
for (const key of Object.getOwnPropertySymbols(Context.internal)) {
Expand Down
27 changes: 22 additions & 5 deletions src/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ export class Context {
return Object.assign(Object.create(this), meta)
}

localize(names: string[]) {
const mapping = Object.create(this.mapping)
for (const name of names) {
mapping[name] = Symbol(name)
}
return this.extend({ mapping })
}

any() {
return this.extend({ filter: () => true })
}
Expand Down Expand Up @@ -84,9 +92,10 @@ export namespace Context {
app: App
state: Plugin.State
filter: Filter
mapping: {}
}

export const internal = {}
export const internal = Object.create(null)

export function service(name: keyof any, options: ServiceOptions = {}) {
if (Object.prototype.hasOwnProperty.call(Context.prototype, name)) return
Expand All @@ -95,17 +104,25 @@ export namespace Context {

Object.defineProperty(Context.prototype, name, {
get(this: Context) {
const value = this.app[privateKey]
const key = this.mapping[name] || privateKey
const value = this.app[key]
if (!value) return
defineProperty(value, Context.current, this)
return value
},
set(this: Context, value) {
const oldValue = this.app[privateKey]
const key = this.mapping[name] || privateKey
const oldValue = this.app[key]
if (oldValue === value) return
this.app[privateKey] = value
this.app[key] = value
if (typeof name !== 'string') return
this.emit('internal/service', name, oldValue)

// trigger event
const self: Context = Object.create(this)
self[Context.filter] = (ctx) => {
return this.mapping[name] === ctx.mapping[name]
}
this.emit(self, 'internal/service', name, oldValue)
},
})

Expand Down
2 changes: 1 addition & 1 deletion src/lifecycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ export interface Events {
'fork': Plugin.Function
'dispose'(): Awaitable<void>
'internal/warn'(format: any, ...param: any[]): void
'internal/service'(name: string, oldValue: any): void
'internal/service'(this: Context, name: string, oldValue: any): void
'internal/update'(state: Plugin.Fork, config: any): void
'internal/hook'(name: string, listener: Function, prepend: boolean): () => boolean
}
34 changes: 34 additions & 0 deletions tests/service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,4 +98,38 @@ describe('Service', () => {
expect(stop.mock.calls).to.have.length(1)
expect(fork.mock.calls).to.have.length(2)
})

it('localize context', async () => {
const app = new App()
const ctx = app.localize(['foo'])

const outer = jest.fn()
const inner = jest.fn()
app.on('internal/service', outer)
ctx.on('internal/service', inner)

app.foo = { bar: 100 }
expect(app.foo).to.deep.equal({ bar: 100 })
expect(ctx.foo).to.be.not.ok
expect(outer.mock.calls).to.have.length(1)
expect(inner.mock.calls).to.have.length(0)

ctx.foo = { bar: 200 }
expect(app.foo).to.deep.equal({ bar: 100 })
expect(ctx.foo).to.deep.equal({ bar: 200 })
expect(outer.mock.calls).to.have.length(1)
expect(inner.mock.calls).to.have.length(1)

app.foo = null
expect(app.foo).to.be.not.ok
expect(ctx.foo).to.deep.equal({ bar: 200 })
expect(outer.mock.calls).to.have.length(2)
expect(inner.mock.calls).to.have.length(1)

ctx.foo = null
expect(app.foo).to.be.not.ok
expect(ctx.foo).to.be.not.ok
expect(outer.mock.calls).to.have.length(2)
expect(inner.mock.calls).to.have.length(2)
})
})

0 comments on commit b78516f

Please sign in to comment.