From f524a89cb6fb83cd641e3e2d4c34df0cce16a8fe Mon Sep 17 00:00:00 2001
From: vsavkin <vic.savkin@gmail.com>
Date: Fri, 10 Oct 2014 11:36:06 -0400
Subject: [PATCH] feat(injector): add support for default bindings

---
 modules/di/src/injector.js                    | 16 +++++++---
 modules/di/test/di/injector_spec.js           | 30 +++++++++++++++++++
 .../src/codegeneration/ClassTransformer.js    |  2 +-
 3 files changed, 43 insertions(+), 5 deletions(-)

diff --git a/modules/di/src/injector.js b/modules/di/src/injector.js
index 93270c17c0..d0d7a0fe06 100644
--- a/modules/di/src/injector.js
+++ b/modules/di/src/injector.js
@@ -19,11 +19,12 @@ function _isWaiting(obj):boolean {
 
 
 export class Injector {
-  constructor(bindings:List, parent:Injector = null) {
+  constructor(bindings:List, {parent=null, defaultBindings=false}={}) {
     var flatten = _flattenBindings(bindings, MapWrapper.create());
     this._bindings = this._createListOfBindings(flatten);
     this._instances = this._createInstances();
     this._parent = parent;
+    this._defaultBindings = defaultBindings;
 
     this._asyncStrategy = new _AsyncInjectorStrategy(this);
     this._syncStrategy = new _SyncInjectorStrategy(this);
@@ -38,7 +39,7 @@ export class Injector {
   }
 
   createChild(bindings:List):Injector {
-    return new Injector(bindings, this);
+    return new Injector(bindings, {parent: this});
   }
 
 
@@ -92,8 +93,15 @@ export class Injector {
   }
 
   _getBinding(key:Key) {
-    if (this._bindings.length <= key.id) return null;
-    return ListWrapper.get(this._bindings, key.id);
+    var binding = this._bindings.length <= key.id ?
+      null :
+      ListWrapper.get(this._bindings, key.id);
+
+    if (isBlank(binding) && this._defaultBindings) {
+      return bind(key.token).toClass(key.token);
+    } else {
+      return binding;
+    }
   }
 
   _markAsConstructing(key:Key) {
diff --git a/modules/di/test/di/injector_spec.js b/modules/di/test/di/injector_spec.js
index 097952a4af..ed9fe97fc8 100644
--- a/modules/di/test/di/injector_spec.js
+++ b/modules/di/test/di/injector_spec.js
@@ -215,6 +215,25 @@ export function main() {
       expect(injector.get(Car)).toBeAnInstanceOf(Car);
     });
 
+    describe("default bindings", function () {
+      it("should be used when no matching binding found", function () {
+        var injector = new Injector([], {defaultBindings: true});
+
+        var car = injector.get(Car);
+
+        expect(car).toBeAnInstanceOf(Car);
+      });
+
+      it("should use the matching binding when it is available", function () {
+        var injector = new Injector([
+          bind(Car).toClass(SportsCar)
+        ], {defaultBindings: true});
+
+        var car = injector.get(Car);
+
+        expect(car).toBeAnInstanceOf(SportsCar);
+      });
+    });
 
     describe("child", function () {
       it('should load instances from parent injector', function () {
@@ -239,6 +258,17 @@ export function main() {
         expect(engineFromParent).not.toBe(engineFromChild);
         expect(engineFromChild).toBeAnInstanceOf(TurboEngine);
       });
+
+      it("should create child injectors without default bindings", function () {
+        var parent = new Injector([], {defaultBindings: true});
+        var child = parent.createChild([]);
+
+        //child delegates to parent the creation of Car
+        var childCar = child.get(Car);
+        var parentCar = parent.get(Car);
+
+        expect(childCar).toBe(parentCar);
+      });
     });
 
     describe("lazy", function () {
diff --git a/tools/transpiler/src/codegeneration/ClassTransformer.js b/tools/transpiler/src/codegeneration/ClassTransformer.js
index a61d73c4e6..d4cf23065b 100644
--- a/tools/transpiler/src/codegeneration/ClassTransformer.js
+++ b/tools/transpiler/src/codegeneration/ClassTransformer.js
@@ -62,7 +62,7 @@ export class ClassTransformer extends ParseTreeTransformer {
         // so that we can use them to set the types of simple-assigned fields.
         elementTree.parameterList.parameters.forEach(function(p) {
           var binding = p.parameter.binding;
-          if (binding.identifierToken) {
+          if (binding && binding.identifierToken) {
             argumentTypesMap[binding.identifierToken.value] = p.typeAnnotation;
           }
         });