Skip to content

Commit

Permalink
Implements #161 (#163)
Browse files Browse the repository at this point in the history
* Working on #142

* working on #142

* working on #142

* implemented #161
  • Loading branch information
remojansen committed Apr 7, 2016
1 parent 115d559 commit fe3da47
Show file tree
Hide file tree
Showing 38 changed files with 294 additions and 286 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -582,7 +582,7 @@ let ninja = kernel.get<INinja>("INinja");
parentContext: [Circular],
rootRequest:
Request {
service: 'INinja',
serviceIdentifier: 'INinja',
parentContext: [Circular],
parentRequest: null,
target: null,
Expand Down
4 changes: 2 additions & 2 deletions src/annotation/inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { tagParameter } from "./decorator_utils";
import * as METADATA_KEY from "../constants/metadata_keys";

// Used to declare types to be injected not available at runtime
function inject(name: (string|Symbol)) {
function inject(serviceIdentifier: (string|Symbol)) {
return function(target: any, targetKey: string, index: number) {
let metadata = new Metadata(METADATA_KEY.INJECT_TAG, name);
let metadata = new Metadata(METADATA_KEY.INJECT_TAG, serviceIdentifier);
return tagParameter(target, targetKey, index, metadata);
};
}
Expand Down
4 changes: 2 additions & 2 deletions src/annotation/multi_inject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import Metadata from "../planning/metadata";
import { tagParameter } from "./decorator_utils";
import * as METADATA_KEY from "../constants/metadata_keys";

function multiInject(name: (string|Symbol)) {
function multiInject(serviceIdentifier: (string|Symbol)) {
return function(target: any, targetKey: string, index: number) {
let metadata = new Metadata(METADATA_KEY.MULTI_INJECT_TAG, name);
let metadata = new Metadata(METADATA_KEY.MULTI_INJECT_TAG, serviceIdentifier);
return tagParameter(target, targetKey, index, metadata);
};
}
Expand Down
6 changes: 3 additions & 3 deletions src/bindings/binding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Binding<T> implements IBinding<T> {
public activated: boolean;

// A runtime identifier because at runtime we don't have interfaces
public runtimeIdentifier: (string|Symbol|INewable<T>);
public serviceIdentifier: (string|Symbol|INewable<T>);

// The constructor of a class which must implement T
public implementationType: INewable<T>;
Expand All @@ -44,9 +44,9 @@ class Binding<T> implements IBinding<T> {
// On activation handler (invoked just before an instance is added to cache and injected)
public onActivation: (context: IContext, injectable: T) => T;

constructor(runtimeIdentifier: (string|Symbol|INewable<T>)) {
constructor(serviceIdentifier: (string|Symbol|INewable<T>)) {
this.activated = false;
this.runtimeIdentifier = runtimeIdentifier;
this.serviceIdentifier = serviceIdentifier;
this.scope = BindingScope.Transient;
this.type = BindingType.Invalid;
this.constraint = (request: IRequest) => { return true; };
Expand Down
6 changes: 3 additions & 3 deletions src/constants/error_msgs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ export const DUPLICATED_INJECTABLE_DECORATOR = "Cannot apply @injectable decorat
export const DUPLICATED_METADATA = "Metadadata key was used more than once in a parameter:";
export const NULL_ARGUMENT = "NULL argument";
export const KEY_NOT_FOUND = "Key Not Found";
export const AMBIGUOUS_MATCH = "Ambiguous match found for service:";
export const CANNOT_UNBIND = "Could not unbind service:";
export const NOT_REGISTERED = "No bindigns found for service:";
export const AMBIGUOUS_MATCH = "Ambiguous match found for serviceIdentifier:";
export const CANNOT_UNBIND = "Could not unbind serviceIdentifier:";
export const NOT_REGISTERED = "No bindigns found for serviceIdentifier:";
export const MISSING_INJECTABLE_ANNOTATION = "Missing required @injectable annotation in:";
export const MISSING_INJECT_ANNOTATION = "Missing required @inject or @multiInject annotation in:";
export const CIRCULAR_DEPENDENCY = "Circular dependency found between services:";
Expand Down
2 changes: 1 addition & 1 deletion src/interfaces/bindings/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

interface IBinding<T> {
activated: boolean;
runtimeIdentifier: (string|Symbol|INewable<T>);
serviceIdentifier: (string|Symbol|INewable<T>);
implementationType: INewable<T>;
factory: IFactoryCreator<any>;
provider: IProviderCreator<any>;
Expand Down
13 changes: 7 additions & 6 deletions src/interfaces/kernel/kernel.d.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
///<reference path="../interfaces.d.ts" />

interface IKernel {
bind<T>(runtimeIdentifier: (string|Symbol|INewable<T>)): IBindingToSyntax<T>;
unbind(runtimeIdentifier: (string|Symbol|any)): void;
bind<T>(serviceIdentifier: (string|Symbol|INewable<T>)): IBindingToSyntax<T>;
unbind(serviceIdentifier: (string|Symbol|any)): void;
unbindAll(): void;
get<T>(runtimeIdentifier: (string|Symbol|INewable<T>)): T;
getNamed<T>(runtimeIdentifier: (string|Symbol|INewable<T>), named: string): T;
getTagged<T>(runtimeIdentifier: (string|Symbol|INewable<T>), key: string, value: any): T;
getAll<T>(runtimeIdentifier: (string|Symbol|INewable<T>)): T[];
get<T>(serviceIdentifier: (string|Symbol|INewable<T>)): T;
getNamed<T>(serviceIdentifier: (string|Symbol|INewable<T>), named: string): T;
getTagged<T>(serviceIdentifier: (string|Symbol|INewable<T>), key: string, value: any): T;
getAll<T>(serviceIdentifier: (string|Symbol|INewable<T>)): T[];
load(...modules: IKernelModule[]): void;
applyMiddleware(...middleware: IMiddleware[]): void;
getServiceIdentifierAsString(serviceIdentifier: (string|Symbol|INewable<any>)): string;
}
2 changes: 1 addition & 1 deletion src/interfaces/kernel/key_value_pair.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
interface IKeyValuePair<T> {
key: (string|Symbol|any);
serviceIdentifier: (string|Symbol|any);
value: Array<T>;
}
8 changes: 4 additions & 4 deletions src/interfaces/kernel/lookup.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
interface ILookup<T> {
add(key: (string|Symbol|any), value: T): void;
get(key: (string|Symbol|any)): Array<T>;
remove(key: (string|Symbol|any)): void;
hasKey(key: (string|Symbol|any)): boolean;
add(serviceIdentifier: (string|Symbol|any), value: T): void;
get(serviceIdentifier: (string|Symbol|any)): Array<T>;
remove(serviceIdentifier: (string|Symbol|any)): void;
hasKey(serviceIdentifier: (string|Symbol|any)): boolean;
}
2 changes: 1 addition & 1 deletion src/interfaces/planning/planner.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
interface IPlanner {
createContext(kernel: IKernel): IContext;
createPlan(parentContext: IContext, binding: IBinding<any>, target: ITarget): IPlan;
getBindings<T>(kernel: IKernel, service: (string|Symbol|INewable<T>)): IBinding<T>[];
getBindings<T>(kernel: IKernel, serviceIdentifier: (string|Symbol|INewable<T>)): IBinding<T>[];
getActiveBindings(parentRequest: IRequest, target: ITarget): IBinding<any>[];
}
4 changes: 2 additions & 2 deletions src/interfaces/planning/request.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
interface IRequest {

/// The service that was requested.
service: (string|Symbol|INewable<any>);
serviceIdentifier: (string|Symbol|INewable<any>);

/// The parent context.
parentContext: IContext;
Expand All @@ -20,7 +20,7 @@ interface IRequest {

// Adds a child request to the request
addChildRequest(
service: (string|Symbol|INewable<any>),
serviceIdentifier: (string|Symbol|INewable<any>),
bindings: (IBinding<any>|IBinding<any>[]),
target: ITarget): IRequest;
}
3 changes: 1 addition & 2 deletions src/interfaces/planning/target.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,14 @@
/// <reference path="./metadata.d.ts" />

interface ITarget {
service: (string|Symbol|INewable<any>);
serviceIdentifier: (string|Symbol|INewable<any>);
name: IQueryableString;
metadata: Array<IMetadata>;
hasTag(key: string): boolean;
isArray(): boolean;
matchesArray(name: string|Symbol|any): boolean;
isNamed(): boolean;
isTagged(): boolean;
getServiceAsString(): string;
matchesNamedTag(name: string): boolean;
matchesTag(key: string): (value: any) => boolean;
}
2 changes: 1 addition & 1 deletion src/interfaces/syntax/binding_to_syntax.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ interface IBindingToSyntax<T> {
toValue(value: T): IBindingWhenOnSyntax<T>;
toConstructor<T2>(constructor: INewable<T2>): IBindingWhenOnSyntax<T>;
toFactory<T2>(factory: IFactoryCreator<T2>): IBindingWhenOnSyntax<T>;
toAutoFactory<T2>(service: (string|Symbol|INewable<T2>)): IBindingWhenOnSyntax<T>;
toAutoFactory<T2>(serviceIdentifier: (string|Symbol|INewable<T2>)): IBindingWhenOnSyntax<T>;
toProvider<T2>(provider: IProviderCreator<T2>): IBindingWhenOnSyntax<T>;
}
55 changes: 34 additions & 21 deletions src/kernel/kernel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,18 @@ class Kernel implements IKernel {
}

// Regiters a type binding
public bind<T>(runtimeIdentifier: (string|Symbol|INewable<T>)): IBindingToSyntax<T> {
let binding = new Binding<T>(runtimeIdentifier);
this._bindingDictionary.add(runtimeIdentifier, binding);
public bind<T>(serviceIdentifier: (string|Symbol|INewable<T>)): IBindingToSyntax<T> {
let binding = new Binding<T>(serviceIdentifier);
this._bindingDictionary.add(serviceIdentifier, binding);
return new BindingToSyntax<T>(binding);
}

// Removes a type binding from the registry by its key
public unbind(runtimeIdentifier: (string|Symbol|any)): void {
public unbind(serviceIdentifier: (string|Symbol|any)): void {
try {
this._bindingDictionary.remove(runtimeIdentifier);
this._bindingDictionary.remove(serviceIdentifier);
} catch (e) {
throw new Error(`${ERROR_MSGS.CANNOT_UNBIND} ${runtimeIdentifier}`);
throw new Error(`${ERROR_MSGS.CANNOT_UNBIND} ${serviceIdentifier}`);
}
}

Expand All @@ -76,31 +76,31 @@ class Kernel implements IKernel {
// Resolves a dependency by its runtime identifier
// The runtime identifier must be associated with only one binding
// use getAll when the runtime identifier is associated with multiple bindings
public get<T>(runtimeIdentifier: (string|Symbol|INewable<T>)): T {
return this._get<T>(runtimeIdentifier, null);
public get<T>(serviceIdentifier: (string|Symbol|INewable<T>)): T {
return this._get<T>(serviceIdentifier, null);
}

public getNamed<T>(runtimeIdentifier: (string|Symbol|INewable<T>), named: string): T {
return this.getTagged<T>(runtimeIdentifier, METADATA_KEY.NAMED_TAG, named);
public getNamed<T>(serviceIdentifier: (string|Symbol|INewable<T>), named: string): T {
return this.getTagged<T>(serviceIdentifier, METADATA_KEY.NAMED_TAG, named);
}

public getTagged<T>(runtimeIdentifier: (string|Symbol|INewable<T>), key: string, value: any): T {
public getTagged<T>(serviceIdentifier: (string|Symbol|INewable<T>), key: string, value: any): T {
let metadata = new Metadata(key, value);
let target = new Target(null, runtimeIdentifier, metadata);
return this._get<T>(runtimeIdentifier, target);
let target = new Target(null, serviceIdentifier, metadata);
return this._get<T>(serviceIdentifier, target);
}

// Resolves a dependency by its runtime identifier
// The runtime identifier can be associated with one or multiple bindings
public getAll<T>(runtimeIdentifier: (string|Symbol|INewable<T>)): T[] {
public getAll<T>(serviceIdentifier: (string|Symbol|INewable<T>)): T[] {

let bindings = this._planner.getBindings<T>(this, runtimeIdentifier);
let bindings = this._planner.getBindings<T>(this, serviceIdentifier);

switch (bindings.length) {

// CASE 1: There are no bindings
case BindingCount.NoBindingsAvailable:
throw new Error(`${ERROR_MSGS.NOT_REGISTERED} ${runtimeIdentifier}`);
throw new Error(`${ERROR_MSGS.NOT_REGISTERED} ${serviceIdentifier}`);

// CASE 2: There is AT LEAST 1 binding
case BindingCount.OnlyOneBindingAvailable:
Expand All @@ -112,15 +112,28 @@ class Kernel implements IKernel {
}
}

private _get<T>(runtimeIdentifier: (string|Symbol|INewable<T>), target: ITarget): T {
public getServiceIdentifierAsString(serviceIdentifier: (string|Symbol|INewable<any>)): string {
let type = typeof serviceIdentifier;
if (type === "function") {
let _serviceIdentifier: any = serviceIdentifier;
return _serviceIdentifier.name;
} else if (type === "symbol") {
return serviceIdentifier.toString();
} else { // string
let _serviceIdentifier: any = serviceIdentifier;
return _serviceIdentifier;
}
}

private _get<T>(serviceIdentifier: (string|Symbol|INewable<T>), target: ITarget): T {

let bindings = this._planner.getBindings<T>(this, runtimeIdentifier);
let bindings = this._planner.getBindings<T>(this, serviceIdentifier);

// Filter bindings using the target and the binding constraints
if (target !== null) {

let request = new Request(
runtimeIdentifier,
serviceIdentifier,
this._planner.createContext(this),
null,
bindings,
Expand All @@ -133,7 +146,7 @@ class Kernel implements IKernel {
if (bindings.length === BindingCount.NoBindingsAvailable) {

// CASE 1: There are no bindings
throw new Error(`${ERROR_MSGS.NOT_REGISTERED} ${runtimeIdentifier}`);
throw new Error(`${ERROR_MSGS.NOT_REGISTERED} ${serviceIdentifier}`);

} else if (bindings.length === BindingCount.OnlyOneBindingAvailable) {

Expand All @@ -143,7 +156,7 @@ class Kernel implements IKernel {
} else {

// CASE 3: There are multiple bindings
throw new Error(`${ERROR_MSGS.AMBIGUOUS_MATCH} ${runtimeIdentifier}`);
throw new Error(`${ERROR_MSGS.AMBIGUOUS_MATCH} ${serviceIdentifier}`);

}

Expand Down
6 changes: 3 additions & 3 deletions src/kernel/key_value_pair.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@

class KeyValuePair<T> implements IKeyValuePair<T> {

public key: string;
public serviceIdentifier: (string|Symbol|any);
public value: Array<T>;

public constructor(key: string, value: T) {
this.key = key;
public constructor(serviceIdentifier: (string|Symbol|any), value: T) {
this.serviceIdentifier = serviceIdentifier;
this.value = new Array<T>();
this.value.push(value);
}
Expand Down
38 changes: 19 additions & 19 deletions src/kernel/lookup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,64 +18,64 @@ class Lookup<T> implements ILookup<T> {
}

// adds a new KeyValuePair to _dictionary
public add(key: (string|Symbol|any), value: T): void {
public add(serviceIdentifier: (string|Symbol|any), value: T): void {

if (key === null || key === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); };
if (serviceIdentifier === null || serviceIdentifier === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); };
if (value === null || value === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); };

let index = this.getIndexByKey(key);
let index = this.getIndexByKey(serviceIdentifier);
if (index !== -1) {
this._dictionary[index].value.push(value);
} else {
this._dictionary.push(new KeyValuePair(key, value));
this._dictionary.push(new KeyValuePair(serviceIdentifier, value));
}
}

// gets the value of a KeyValuePair by its key
public get(key: (string|Symbol|any)): Array<T> {
// gets the value of a KeyValuePair by its serviceIdentifier
public get(serviceIdentifier: (string|Symbol|any)): Array<T> {

if (key === null || key === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); }
if (serviceIdentifier === null || serviceIdentifier === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); }

let index = this.getIndexByKey(key);
let index = this.getIndexByKey(serviceIdentifier);
if (index !== -1) {
return this._dictionary[index].value;
} else {
throw new Error(ERROR_MSGS.KEY_NOT_FOUND);
}
}

// removes a KeyValuePair from _dictionary by its key
public remove(key: (string|Symbol|any)): void {
// removes a KeyValuePair from _dictionary by its serviceIdentifier
public remove(serviceIdentifier: (string|Symbol|any)): void {

if (key === null || key === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); }
if (serviceIdentifier === null || serviceIdentifier === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); }

let index = this.getIndexByKey(key);
let index = this.getIndexByKey(serviceIdentifier);
if (index !== -1) {
this._dictionary.splice(index, 1);
} else {
throw new Error(ERROR_MSGS.KEY_NOT_FOUND);
}
}

// returns true if _dictionary contains key
public hasKey(key: (string|Symbol|any)): boolean {
// returns true if _dictionary contains serviceIdentifier
public hasKey(serviceIdentifier: (string|Symbol|any)): boolean {

if (key === null || key === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); }
if (serviceIdentifier === null || serviceIdentifier === undefined) { throw new Error(ERROR_MSGS.NULL_ARGUMENT); }

let index = this.getIndexByKey(key);
let index = this.getIndexByKey(serviceIdentifier);
if (index !== -1) {
return true;
} else {
return false;
}
}

// finds the location of a KeyValuePair pair in _dictionary by its key
private getIndexByKey(key: (string|Symbol|any)): number {
// finds the location of a KeyValuePair pair in _dictionary by its serviceIdentifier
private getIndexByKey(serviceIdentifier: (string|Symbol|any)): number {
let index = -1;
for (let i = 0; i < this._dictionary.length; i++) {
let keyValuePair = this._dictionary[i];
if (keyValuePair.key === key) {
if (keyValuePair.serviceIdentifier === serviceIdentifier) {
index = i;
}
}
Expand Down
Loading

0 comments on commit fe3da47

Please sign in to comment.