Skip to content

Commit

Permalink
fix(context): allow session to be passed into @inject.getter
Browse files Browse the repository at this point in the history
The current session will be cloned to create an isolated scope
for the getter function to resume
  • Loading branch information
raymondfeng committed Jan 16, 2018
1 parent 5c35ccd commit 0517ea1
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 5 deletions.
2 changes: 1 addition & 1 deletion packages/context/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export {
} from './binding';

export {Context} from './context';
export {Constructor} from './resolver';
export {Constructor, ResolutionSession} from './resolver';
export {inject, Setter, Getter} from './inject';
export {Provider} from './provider';
export {isPromise} from './is-promise';
Expand Down
11 changes: 8 additions & 3 deletions packages/context/src/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,15 @@ export namespace inject {
};
}

function resolveAsGetter(ctx: Context, injection: Injection) {
// No resolution session should be propagated into the getter
function resolveAsGetter(
ctx: Context,
injection: Injection,
session?: ResolutionSession,
) {
// We need to clone the session for the getter as it will be resolved later
if (session != null) session = session.clone();
return function getter() {
return ctx.get(injection.bindingKey);
return ctx.get(injection.bindingKey, session);
};
}

Expand Down
11 changes: 11 additions & 0 deletions packages/context/src/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,17 @@ export class ResolutionSession {

readonly injections: Injection[] = [];

/**
* Take a snapshot of the ResolutionSession so that we can pass it to
* `@inject.getter` without interferring with the current session
*/
clone() {
const copy = new ResolutionSession();
copy.bindings.push(...this.bindings);
copy.injections.push(...this.injections);
return copy;
}

/**
* Start to resolve a binding within the session
* @param binding Binding
Expand Down
36 changes: 35 additions & 1 deletion packages/context/test/unit/resolver.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import {
instantiateClass,
invokeMethod,
Injection,
Constructor,
Getter,
ResolutionSession,
} from '../..';
import {ResolutionSession} from '../../src/resolver';

describe('constructor injection', () => {
let ctx: Context;
Expand Down Expand Up @@ -196,6 +198,38 @@ describe('constructor injection', () => {
expect(bindingPath).to.eql('x --> y --> z');
});

it('tracks path of bindings for @inject.getter', async () => {
const context = new Context();
let bindingPath = '';

class ZClass {
@inject(
'p',
{},
// Set up a custom resolve() to access information from the session
(c: Context, injection: Injection, session: ResolutionSession) => {
bindingPath = session.getBindingPath();
},
)
myProp: string;
}

class YClass {
constructor(@inject.getter('z') public z: Getter<ZClass>) {}
}

class XClass {
constructor(@inject('y') public y: YClass) {}
}

context.bind('x').toClass(XClass);
context.bind('y').toClass(YClass);
context.bind('z').toClass(ZClass);
const x: XClass = context.getSync('x');
await x.y.z();
expect(bindingPath).to.eql('x --> y --> z');
});

it('tracks path of injections', () => {
const context = new Context();
let injectionPath = '';
Expand Down

0 comments on commit 0517ea1

Please sign in to comment.