Skip to content

Commit

Permalink
Merge pull request #141 from remojansen/master
Browse files Browse the repository at this point in the history
Implemented #116
  • Loading branch information
remojansen committed Mar 24, 2016
2 parents 6162589 + a4461c2 commit 8a835c2
Show file tree
Hide file tree
Showing 38 changed files with 1,547 additions and 170 deletions.
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
[![Dependencies](https://david-dm.org/inversify/InversifyJS.svg)](https://david-dm.org/inversify/InversifyJS#info=dependencies)
[![img](https://david-dm.org/inversify/InversifyJS/dev-status.svg)](https://david-dm.org/inversify/InversifyJS/#info=devDependencies)
[![img](https://david-dm.org/inversify/InversifyJS/peer-status.svg)](https://david-dm.org/inversify/InversifyJS/#info=peerDependenciess)
[![Known Vulnerabilities](https://snyk.io/test/github/inversify/InversifyJS/badge.svg)](https://snyk.io/test/github/inversify/InversifyJS)

<img src="https://raw.githubusercontent.com/inversify/inversify.github.io/master/img/logo.png" width="500" />

Expand Down Expand Up @@ -647,6 +648,42 @@ interface IQueryableString {
value(): string;
}
```
We have included some helpers to facilitate the creation of custom constraints:
```
import { Kernel, traverseAncerstors, taggedConstraint, namedConstraint, typeConstraint } from "inversify";
let whenParentNamedCanThrowConstraint = (request: IRequest) => {
return namedConstraint("canThrow")(request.parentRequest);
};
let whenAnyAncestorIsConstraint = (request: IRequest) => {
return traverseAncerstors(request, typeConstraint(Ninja));
};
let whenAnyAncestorTaggedConstraint = (request: IRequest) => {
return traverseAncerstors(request, taggedConstraint("canThrow")(true));
};
```
The InversifyJS fluent syntax for bindings includes some already implemented common contextual constraints:
```
interface IBindingWhenSyntax<T> {
when(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>;
whenTargetNamed(name: string): IBindingOnSyntax<T>;
whenTargetTagged(tag: string, value: any): IBindingOnSyntax<T>;
whenInjectedInto(parent: (Function|string)): IBindingOnSyntax<T>;
whenParentNamed(name: string): IBindingOnSyntax<T>;
whenParentTagged(tag: string, value: any): IBindingOnSyntax<T>;
whenAnyAncestorIs(ancestor: (Function|string)): IBindingOnSyntax<T>;
whenNoAncestorIs(ancestor: (Function|string)): IBindingOnSyntax<T>;
whenAnyAncestorNamed(name: string): IBindingOnSyntax<T>;
whenAnyAncestorTagged(tag: string, value: any): IBindingOnSyntax<T>;
whenNoAncestorNamed(name: string): IBindingOnSyntax<T>;
whenNoAncestorTagged(tag: string, value: any): IBindingOnSyntax<T>;
whenAnyAncestorMatches(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>;
whenNoAncestorMatches(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>;
}
```

#### Circular dependencies
InversifyJS is able to identify circular dependencies and will throw an exception to help you to
Expand All @@ -659,7 +696,8 @@ Error: Circular dependency found between services: IKatana and INinja
Plese refer to the [wiki](https://github.com/inversify/InversifyJS/wiki) for additional details.

### Live demo & examples
You can try InversifyJS online at [tonicdev.com](https://tonicdev.com/remojansen/inversify-2.0.0-alpha.3). Some integration examples are available in the [official examples repository](https://github.com/inversify/Inversify-code-samples).
You can try InversifyJS online at [tonicdev.com](https://tonicdev.com/remojansen/inversify-2.0.0-alpha.3).
Some integration examples are available in the [official examples repository](https://github.com/inversify/Inversify-code-samples).

### Testimonies

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "inversify",
"version": "2.0.0-alpha.6",
"version": "2.0.0-alpha.7",
"description": "A lightweight IoC container written in TypeScript.",
"main": "lib/inversify.js",
"jsnext:main": "es/inversify.js",
Expand Down
3 changes: 1 addition & 2 deletions src/annotation/injectable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import * as METADATA_KEY from "../constants/metadata_keys";
import * as ERRORS_MSGS from "../constants/error_msgs";
import guid from "../utils/utils";

function injectable(...paramTypes: string[]) {
return function(target: any) {
Expand All @@ -12,7 +11,7 @@ function injectable(...paramTypes: string[]) {
}

Reflect.defineMetadata(METADATA_KEY.INJECTABLE, paramTypes, target);
Reflect.defineMetadata(METADATA_KEY.TYPE_ID, guid(), target);
Reflect.defineMetadata(METADATA_KEY.TYPE_ID, Symbol(), target);

return target;
};
Expand Down
3 changes: 2 additions & 1 deletion src/annotation/named.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import Metadata from "../planning/metadata";
import { tagParameter } from "./decorator_utils";
import * as METADATA_KEY from "../constants/metadata_keys";

// Used to add named metadata which is used to resolve name-based contextual bindings.
function named(name: string) {
return function(target: any, targetKey: string, index: number) {
let metadata = new Metadata("named", name);
let metadata = new Metadata(METADATA_KEY.NAMED_TAG, name);
return tagParameter(target, targetKey, index, metadata);
};
}
Expand Down
4 changes: 2 additions & 2 deletions src/bindings/binding_scope.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
///<reference path="../interfaces/interfaces.d.ts" />

enum BindingScope {
Transient,
Singleton
Transient = 0,
Singleton = 1
}

export default BindingScope;
1 change: 1 addition & 0 deletions src/constants/error_msgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ export const NOT_REGISTERED = "No bindigns found for service:";
export const CIRCULAR_DEPENDENCY = "Circular dependency found between services:";
export const NOT_IMPLEMENTED = "Sorry, this feature is not fully implemented yet.";
export const INVALID_BINDING_TYPE = "Invalid binding type:";
export const NOT_INJECTABLE = "// TODO";
1 change: 1 addition & 0 deletions src/constants/metadata_keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export const TAGGED = "inversify:tagged";
export const INJECTABLE = "inversify:injectable";
export const TYPE_ID = "inversify:type_id";
export const PARAM_NAMES = "inversify:param_names";
export const NAMED_TAG = "named";
7 changes: 7 additions & 0 deletions src/interfaces/annotations/symbol.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/// <reference path="../interfaces.d.ts" />

interface SymbolConstructor {
(description?: string|number): symbol;
}

declare var Symbol: SymbolConstructor;
7 changes: 7 additions & 0 deletions src/interfaces/interfaces.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
/// <reference path="./kernel/key_value_pair.d.ts" />
/// <reference path="./kernel/lookup.d.ts" />

// ANNOTATION
/// <reference path="./annotations/symbol.d.ts" />

// PLANNING
/// <reference path="./planning/planner.d.ts" />
/// <reference path="./planning/plan.d.ts" />
Expand All @@ -32,4 +35,8 @@

// SYNTAX
/// <reference path="./syntax/binding_to_syntax.d.ts" />
/// <reference path="./syntax/binding_in_syntax.d.ts" />
/// <reference path="./syntax/binding_when_syntax.d.ts" />
/// <reference path="./syntax/binding_on_syntax.d.ts" />
/// <reference path="./syntax/binding_when_on_syntax.d.ts" />
/// <reference path="./syntax/binding_in_when_on_syntax.d.ts" />
5 changes: 5 additions & 0 deletions src/interfaces/syntax/binding_in_syntax.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference path="../interfaces.d.ts" />

interface IBindingInSyntax<T> {
inSingletonScope(): IBindingWhenOnSyntax<T>;
}
9 changes: 1 addition & 8 deletions src/interfaces/syntax/binding_in_when_on_syntax.d.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
/// <reference path="../interfaces.d.ts" />

interface IBindingInWhenOnSyntax<T> {
inTransientScope(): IBindingInWhenOnSyntax<T>;
inSingletonScope(): IBindingInWhenOnSyntax<T>;
when(constraint: (request: IRequest) => boolean): IBindingInWhenOnSyntax<T>;
whenTargetNamed(name: string): IBindingInWhenOnSyntax<T>;
whenTargetTagged(tag: string, value: any): IBindingInWhenOnSyntax<T>;
onActivation(fn: (context: IContext, injectable: T) => T): IBindingInWhenOnSyntax<T>;
}
interface IBindingInWhenOnSyntax<T> extends IBindingInSyntax<T>, IBindingWhenOnSyntax<T> {}
5 changes: 5 additions & 0 deletions src/interfaces/syntax/binding_on_syntax.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference path="../interfaces.d.ts" />

interface IBindingOnSyntax<T> {
onActivation(fn: (context: IContext, injectable: T) => T): IBindingWhenSyntax<T>;
}
10 changes: 5 additions & 5 deletions src/interfaces/syntax/binding_to_syntax.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

interface IBindingToSyntax<T> {
to(constructor: { new(...args: any[]): T; }): IBindingInWhenOnSyntax<T>;
toValue(value: T): IBindingInWhenOnSyntax<T>;
toConstructor<T2>(constructor: INewable<T2>): IBindingInWhenOnSyntax<T>;
toFactory<T2>(factory: IFactoryCreator<T2>): IBindingInWhenOnSyntax<T>;
toAutoFactory<T2>(): IBindingInWhenOnSyntax<T>;
toProvider<T2>(provider: IProviderCreator<T2>): IBindingInWhenOnSyntax<T>;
toValue(value: T): IBindingWhenOnSyntax<T>;
toConstructor<T2>(constructor: INewable<T2>): IBindingWhenOnSyntax<T>;
toFactory<T2>(factory: IFactoryCreator<T2>): IBindingWhenOnSyntax<T>;
toAutoFactory<T2>(): IBindingWhenOnSyntax<T>;
toProvider<T2>(provider: IProviderCreator<T2>): IBindingWhenOnSyntax<T>;
}
3 changes: 3 additions & 0 deletions src/interfaces/syntax/binding_when_on_syntax.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/// <reference path="../interfaces.d.ts" />

interface IBindingWhenOnSyntax<T> extends IBindingWhenSyntax<T>, IBindingOnSyntax<T> {}
18 changes: 18 additions & 0 deletions src/interfaces/syntax/binding_when_syntax.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
/// <reference path="../interfaces.d.ts" />

interface IBindingWhenSyntax<T> {
when(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>;
whenTargetNamed(name: string): IBindingOnSyntax<T>;
whenTargetTagged(tag: string, value: any): IBindingOnSyntax<T>;
whenInjectedInto(parent: (Function|string)): IBindingOnSyntax<T>;
whenParentNamed(name: string): IBindingOnSyntax<T>;
whenParentTagged(tag: string, value: any): IBindingOnSyntax<T>;
whenAnyAncestorIs(ancestor: (Function|string)): IBindingOnSyntax<T>;
whenNoAncestorIs(ancestor: (Function|string)): IBindingOnSyntax<T>;
whenAnyAncestorNamed(name: string): IBindingOnSyntax<T>;
whenAnyAncestorTagged(tag: string, value: any): IBindingOnSyntax<T>;
whenNoAncestorNamed(name: string): IBindingOnSyntax<T>;
whenNoAncestorTagged(tag: string, value: any): IBindingOnSyntax<T>;
whenAnyAncestorMatches(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>;
whenNoAncestorMatches(constraint: (request: IRequest) => boolean): IBindingOnSyntax<T>;
}
5 changes: 5 additions & 0 deletions src/inversify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,15 @@ import tagged from "./annotation/tagged";
import named from "./annotation/named";
import paramNames from "./annotation/paramnames";
import { decorate } from "./annotation/decorator_utils";
import { traverseAncerstors, taggedConstraint, namedConstraint, typeConstraint } from "./syntax/constraint_helpers";

export { Kernel };
export { decorate };
export { injectable };
export { tagged };
export { named };
export { paramNames };
export { traverseAncerstors };
export { taggedConstraint };
export { namedConstraint };
export { typeConstraint };
4 changes: 0 additions & 4 deletions src/planning/request.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
///<reference path="../interfaces/interfaces.d.ts" />

import guid from "../utils/utils";

class Request implements IRequest {

public guid: string;
public service: string;
public parentContext: IContext;
public parentRequest: IRequest;
Expand All @@ -19,7 +16,6 @@ class Request implements IRequest {
bindings: (IBinding<any>|IBinding<any>[]),
target: ITarget = null) {

this.guid = guid();
this.service = service;
this.parentContext = parentContext;
this.parentRequest = parentRequest;
Expand Down
9 changes: 5 additions & 4 deletions src/planning/target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import Metadata from "../planning/metadata";
import QueryableString from "./queryable_string";
import * as METADATA_KEY from "../constants/metadata_keys";

class Target implements ITarget {

Expand All @@ -18,7 +19,7 @@ class Target implements ITarget {

// is named target
if (typeof namedOrTagged === "string") {
metadataItem = new Metadata("named", namedOrTagged);
metadataItem = new Metadata(METADATA_KEY.NAMED_TAG, namedOrTagged);
} else if (namedOrTagged instanceof Metadata) {
// is target with metadata
metadataItem = namedOrTagged;
Expand All @@ -37,7 +38,7 @@ class Target implements ITarget {
public isNamed(): boolean {
for (let i = 0; i < this.metadata.length; i++) {
let m = this.metadata[i];
if (m.key === "named") {
if (m.key === METADATA_KEY.NAMED_TAG) {
return true;
}
}
Expand All @@ -47,7 +48,7 @@ class Target implements ITarget {
public isTagged(): boolean {
for (let i = 0; i < this.metadata.length; i++) {
let m = this.metadata[i];
if (m.key !== "named") {
if (m.key !== METADATA_KEY.NAMED_TAG) {
return true;
}
}
Expand All @@ -57,7 +58,7 @@ class Target implements ITarget {
public matchesName(name: string): boolean {
for (let i = 0; i < this.metadata.length; i++) {
let m = this.metadata[i];
if (m.key === "named" && m.value === name) {
if (m.key === METADATA_KEY.NAMED_TAG && m.value === name) {
return true;
}
}
Expand Down
21 changes: 21 additions & 0 deletions src/syntax/binding_in_syntax.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
///<reference path="../interfaces/interfaces.d.ts" />

import BindingScope from "../bindings/binding_scope";
import BindingWhenOnSyntax from "./binding_when_on_syntax";

class BindingInSyntax<T> implements IBindingInSyntax<T> {

private _binding: IBinding<T>;

public constructor(binding: IBinding<T>) {
this._binding = binding;
}

public inSingletonScope(): IBindingWhenOnSyntax<T> {
this._binding.scope = BindingScope.Singleton;
return new BindingWhenOnSyntax<T>(this._binding);
}

}

export default BindingInSyntax;
Loading

0 comments on commit 8a835c2

Please sign in to comment.