Skip to content

Commit

Permalink
feat(context): make bindings as event emitters to report changes
Browse files Browse the repository at this point in the history
  • Loading branch information
raymondfeng committed Jan 10, 2020
1 parent 3e15bca commit cb1f10c
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 1 deletion.
63 changes: 63 additions & 0 deletions packages/context/src/__tests__/unit/binding.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ describe('Binding', () => {
/Tag must be a string or an object \(but not array\):/,
);
});

it('triggers changed event', () => {
const events: unknown[] = [];
binding.on('changed', (b, op) => {
events.push({binding: b, op});
});
binding.tag('t1');
expect(events).to.eql([{binding, op: 'tag'}]);
});
});

describe('inScope', () => {
Expand All @@ -99,6 +108,15 @@ describe('Binding', () => {
binding.inScope(BindingScope.TRANSIENT);
expect(binding.scope).to.equal(BindingScope.TRANSIENT);
});

it('triggers changed event', () => {
const events: unknown[] = [];
binding.on('changed', (b, op) => {
events.push({binding: b, op});
});
binding.inScope(BindingScope.TRANSIENT);
expect(events).to.eql([{binding, op: 'scope'}]);
});
});

describe('applyDefaultScope', () => {
Expand All @@ -125,6 +143,15 @@ describe('Binding', () => {
expect(binding.type).to.equal(BindingType.CONSTANT);
});

it('triggers changed event', () => {
const events: unknown[] = [];
binding.on('changed', (b, op) => {
events.push({binding: b, op});
});
binding.to('value');
expect(events).to.eql([{binding, op: 'value'}]);
});

it('rejects promise values', () => {
expect(() => binding.to(Promise.resolve('value'))).to.throw(
/Promise instances are not allowed.*toDynamicValue/,
Expand All @@ -150,6 +177,15 @@ describe('Binding', () => {
expect(value).to.equal('hello');
expect(b.type).to.equal(BindingType.DYNAMIC_VALUE);
});

it('triggers changed event', () => {
const events: unknown[] = [];
binding.on('changed', (b, op) => {
events.push({binding: b, op});
});
binding.toDynamicValue(() => Promise.resolve('hello'));
expect(events).to.eql([{binding, op: 'value'}]);
});
});

describe('toClass(cls)', () => {
Expand All @@ -160,6 +196,15 @@ describe('Binding', () => {
const myService = await ctx.get<MyService>('myService');
expect(myService.getMessage()).to.equal('hello world');
});

it('triggers changed event', () => {
const events: unknown[] = [];
binding.on('changed', (b, op) => {
events.push({binding: b, op});
});
binding.toClass(MyService);
expect(events).to.eql([{binding, op: 'value'}]);
});
});

describe('toProvider(provider)', () => {
Expand Down Expand Up @@ -195,6 +240,15 @@ describe('Binding', () => {
const b = ctx.bind('provider_key').toProvider(MyProvider);
expect(b.providerConstructor).to.equal(MyProvider);
});

it('triggers changed event', () => {
const events: unknown[] = [];
binding.on('changed', (b, op) => {
events.push({binding: b, op});
});
binding.toProvider(MyProvider);
expect(events).to.eql([{binding, op: 'value'}]);
});
});

describe('toAlias(bindingKeyWithPath)', () => {
Expand Down Expand Up @@ -260,6 +314,15 @@ describe('Binding', () => {
.toAlias('parent.options#child');
expect(childBinding.type).to.equal(BindingType.ALIAS);
});

it('triggers changed event', () => {
const events: unknown[] = [];
binding.on('changed', (b, op) => {
events.push({binding: b, op});
});
binding.toAlias('parent.options#child');
expect(events).to.eql([{binding, op: 'value'}]);
});
});

describe('apply(templateFn)', () => {
Expand Down
7 changes: 6 additions & 1 deletion packages/context/src/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// License text available at https://opensource.org/licenses/MIT

import debugFactory from 'debug';
import {EventEmitter} from 'events';
import {BindingAddress, BindingKey} from './binding-key';
import {Context} from './context';
import {createProxyWithInterceptors} from './interception-proxy';
Expand Down Expand Up @@ -148,7 +149,7 @@ type ValueGetter<T> = (
* Binding represents an entry in the `Context`. Each binding has a key and a
* corresponding value getter.
*/
export class Binding<T = BoundValue> {
export class Binding<T = BoundValue> extends EventEmitter {
/**
* Key of the binding
*/
Expand Down Expand Up @@ -199,6 +200,7 @@ export class Binding<T = BoundValue> {
}

constructor(key: BindingAddress<T>, public isLocked: boolean = false) {
super();
BindingKey.validate(key);
this.key = key.toString();
}
Expand Down Expand Up @@ -362,6 +364,7 @@ export class Binding<T = BoundValue> {
Object.assign(this.tagMap, t);
}
}
this.emit('changed', this, 'tag');
return this;
}

Expand All @@ -379,6 +382,7 @@ export class Binding<T = BoundValue> {
inScope(scope: BindingScope): this {
if (this._scope !== scope) this._clearCache();
this._scope = scope;
this.emit('changed', this, 'scope');
return this;
}

Expand Down Expand Up @@ -409,6 +413,7 @@ export class Binding<T = BoundValue> {
}
return getValue(ctx, options);
};
this.emit('changed', this, 'value');
}

/**
Expand Down

0 comments on commit cb1f10c

Please sign in to comment.