Repository: abuiles/ember-watson (js)

Issue:
import 'Ember' module when needed
When running `ember convert-prototype-extensions`

In some cases if looks like this will create a reference to `Ember.computed` even if Ember is not made available within the scope of the file.

It would be nice if you could check for this and insert 

```
import Ember from 'ember';
```

at the top of the file.

Apologies if this has already been discussed.

ember watson is a cool project. Great work.

Pull request:
Include `import Ember from 'ember'` if not defined (closes #24).

Patch:
diff --git a/lib/formulas/helpers/add-default-import.js b/lib/formulas/helpers/add-default-import.js
new file mode 100644
index 0000000..4aeea2d
--- /dev/null
+++ b/lib/formulas/helpers/add-default-import.js
@@ -0,0 +1,15 @@
+var builders = require('recast').types.builders;
+
+module.exports = function(ast, moduleName, identifier) {
+  var importDefaultSpecifier = [builders.importDefaultSpecifier(
+    builders.identifier(identifier)
+  )];
+  var importDeclaration = builders.importDeclaration(
+    importDefaultSpecifier,
+    builders.moduleSpecifier(moduleName)
+  );
+
+  ast.program.body.unshift(importDeclaration);
+
+  return ast;
+};
diff --git a/lib/formulas/helpers/is-import-for.js b/lib/formulas/helpers/is-import-for.js
new file mode 100644
index 0000000..11502dd
--- /dev/null
+++ b/lib/formulas/helpers/is-import-for.js
@@ -0,0 +1,4 @@
+module.exports = function isImportFor(module, node) {
+  return node.source.type === 'ModuleSpecifier' &&
+    node.source.value === module;
+};
diff --git a/lib/formulas/prototype-extension-transforms.js b/lib/formulas/prototype-extension-transforms.js
index 9ea62ac..b2fdff5 100644
--- a/lib/formulas/prototype-extension-transforms.js
+++ b/lib/formulas/prototype-extension-transforms.js
@@ -1,5 +1,9 @@
-var recast   = require('recast');
-var builders = recast.types.builders;
+var recast           = require('recast');
+var builders         = recast.types.builders;
+var addDefaultImport = require('./helpers/add-default-import');
+var isImportFor      = require('./helpers/is-import-for');
+
+
 
 function transformExtension(path, type) {
   var node = path.node;
@@ -51,7 +55,8 @@ module.exports = function transform(source) {
   var sections = {
     computedProperties: [],
     observers: [],
-    eventObservers: []
+    eventObservers: [],
+    addEmberImport: true
   };
 
   var ast = recast.parse(source);
@@ -72,6 +77,13 @@ module.exports = function transform(source) {
         sections.eventObservers.push(path);
       }
 
+      this.traverse(path);
+    },
+    visitImportDeclaration: function(path) {
+      if (isImportFor('ember', path.node)) {
+        sections.addEmberImport = false;
+      }
+
       this.traverse(path);
     }
   });
@@ -80,6 +92,8 @@ module.exports = function transform(source) {
   sections.computedProperties.forEach(transformComputedProperty);
   sections.eventObservers.forEach(transformEventObserver);
 
-
+  if (sections.addEmberImport) {
+    addDefaultImport(ast, 'ember', 'Ember');
+  }
   return recast.print(ast, { tabWidth: 2, quote: 'single' }).code;
 };
diff --git a/lib/formulas/qunit-transforms.js b/lib/formulas/qunit-transforms.js
index 963ee1e..c3c6e28 100644
--- a/lib/formulas/qunit-transforms.js
+++ b/lib/formulas/qunit-transforms.js
@@ -1,5 +1,6 @@
-var recast   = require('recast');
-var builders = recast.types.builders;
+var recast      = require('recast');
+var builders    = recast.types.builders;
+var isImportFor = require('./helpers/is-import-for');
 
 var ASSERTIONS = [
   'async',
@@ -51,11 +52,6 @@ function isAssertion(node) {
     ASSERTIONS.indexOf(node.expression.callee.name) != -1;
 }
 
-function isImportFor(module, node) {
-  return node.source.type === 'ModuleSpecifier' &&
-    node.source.value === module;
-}
-
 function transformModule(node) {
   var callExpression = node.expression;
   if (callExpression.arguments.length > 1 &&


Test patch:
diff --git a/tests/fixtures/prototype-extension-files/new-with-ember.js b/tests/fixtures/prototype-extension-files/new-with-ember.js
new file mode 100644
index 0000000..4de62a7
--- /dev/null
+++ b/tests/fixtures/prototype-extension-files/new-with-ember.js
@@ -0,0 +1,34 @@
+import Ember from 'ember';
+export default Ember.Controller.extend({
+  hasNoDependency: Ember.computed(function() {
+    return true;
+  }),
+
+  hasMultipleDependencies: Ember.computed('foo', 'bar', function() {
+    return this.getProperties('foo', 'bar');
+  }),
+
+  chainedCP: Ember.computed('foo', function() {
+    return false;
+  }).volatile().readOnly(),
+
+  isNotExtendingPrototype: Ember.computed(function() {
+    return true;
+  }),
+
+  isNotExtendingPrototypeWithDependencies: Ember.computed('foo', function() {
+    return this.get('foo');
+  }),
+
+  simpleObserver: Ember.observer('foo', function() {
+    this.set('bar', true);
+  }),
+
+  chainedObserver: Ember.on('init', Ember.observer('foo', 'bar', function(property) {
+    this.set('baz', true);
+  })),
+
+  onInit: Ember.on('init', function() {
+    this.set('foobar', true);
+  })
+});
diff --git a/tests/fixtures/prototype-extension-files/old-without-ember.js b/tests/fixtures/prototype-extension-files/old-without-ember.js
new file mode 100644
index 0000000..d89ce37
--- /dev/null
+++ b/tests/fixtures/prototype-extension-files/old-without-ember.js
@@ -0,0 +1,33 @@
+export default Ember.Controller.extend({
+  hasNoDependency: function() {
+    return true;
+  }.property(),
+
+  hasMultipleDependencies: function() {
+    return this.getProperties('foo', 'bar');
+  }.property('foo', 'bar'),
+
+  chainedCP: function() {
+    return false;
+  }.property('foo').volatile().readOnly(),
+
+  isNotExtendingPrototype: Ember.computed(function() {
+    return true;
+  }),
+
+  isNotExtendingPrototypeWithDependencies: Ember.computed('foo', function() {
+    return this.get('foo');
+  }),
+
+  simpleObserver: function() {
+    this.set('bar', true);
+  }.observes('foo'),
+
+  chainedObserver: function(property) {
+    this.set('baz', true);
+  }.observes('foo', 'bar').on('init'),
+
+  onInit: function() {
+    this.set('foobar', true);
+  }.on('init')
+});
diff --git a/tests/prototype-extension-migrator-test.js b/tests/prototype-extension-migrator-test.js
index 5d3b11c..be01206 100644
--- a/tests/prototype-extension-migrator-test.js
+++ b/tests/prototype-extension-migrator-test.js
@@ -11,4 +11,12 @@ describe('computed properties, observers and event observers extending prototype
 
     astEquality(newSource, fs.readFileSync('./tests/fixtures/prototype-extension-files/new.js'));
   });
+
+  it('includes Ember if not imported', function() {
+    var source = fs.readFileSync('./tests/fixtures/prototype-extension-files/old-without-ember.js');
+    var watson = new Watson();
+    var newSource = watson._transformPrototypeExtensions(source);
+
+    astEquality(newSource, fs.readFileSync('./tests/fixtures/prototype-extension-files/new-with-ember.js'));
+  });
 });