Repository: rwjblue/ember-cli-template-lint
Pull request #84 (2016-04-17 17:23:27)

[feature deprecated-each-syntax] Linting for each
This covers deprecations for the `in` syntax of `{{#each}}`, such as
`{{#each post in posts}}`.

rwjblue: Looks great! 

* Can we put deprecation related plugins into a subdir for deprecations?
* Can you add a section to the README for deprecations, and add this rules info in that section?
* Can you enable this rule by default in the blueprint?

Patch:
diff --git a/README.md b/README.md
index ade2362..05d27a4 100644
--- a/README.md
+++ b/README.md
@@ -187,6 +187,30 @@ Whitelist of option in the configuration (are tags name or element attributes):
   * `textarea`
   * `tabindex`
 
+### Deprecations
+
+#### deprecated-each-syntax
+
+In Ember 2.0, support for using the `in` form of the `{{#each}}` helper
+has been removed.
+
+For example, this rule forbids the following:
+
+```hbs
+{{{#each post in posts}}}
+  <li>{{post.name}}</li>
+{{/each}}
+```
+
+Instead, you should write the template as:
+
+```hbs
+{{#each posts as |post|}}
+  <li>{{post.name}}</li>
+{{/each}}
+```
+
+More information is available at the [Deprecation Guide](http://emberjs.com/deprecations/v1.x/#toc_code-in-code-syntax-for-code-each-code).
 
 ## Contributing
 
diff --git a/blueprints/ember-cli-template-lint/files/.template-lintrc.js b/blueprints/ember-cli-template-lint/files/.template-lintrc.js
index 715dcfd..1ebb50b 100644
--- a/blueprints/ember-cli-template-lint/files/.template-lintrc.js
+++ b/blueprints/ember-cli-template-lint/files/.template-lintrc.js
@@ -6,5 +6,6 @@ module.exports = {
   'block-indentation': 2,
   'html-comments': true,
   'nested-interactive': true,
-  'triple-curlies': true
+  'triple-curlies': true,
+  'deprecated-each-syntax': true
 };
diff --git a/ext/helpers/ast-node-info.js b/ext/helpers/ast-node-info.js
index c6c0a30..c2a56a0 100644
--- a/ext/helpers/ast-node-info.js
+++ b/ext/helpers/ast-node-info.js
@@ -18,4 +18,8 @@ AstNodeInfo.isElementNode = function(node) {
   return node.type === 'ElementNode';
 };
 
+AstNodeInfo.isBlockStatement = function(node) {
+  return node.type === 'BlockStatement';
+};
+
 module.exports = AstNodeInfo;
diff --git a/ext/plugins/deprecations/lint-deprecated-each-syntax.js b/ext/plugins/deprecations/lint-deprecated-each-syntax.js
new file mode 100644
index 0000000..a075c06
--- /dev/null
+++ b/ext/plugins/deprecations/lint-deprecated-each-syntax.js
@@ -0,0 +1,42 @@
+'use strict';
+
+var buildPlugin = require('../base');
+var astInfo = require('../../helpers/ast-node-info');
+var calculateLocationDisplay = require('../../helpers/calculate-location-display');
+
+var DEPRECATION_URL = 'http://emberjs.com/deprecations/v1.x/#toc_code-in-code-syntax-for-code-each-code';
+
+module.exports = function(addonContext) {
+
+  var DeprecatedEachSyntax = buildPlugin(addonContext, 'deprecated-each-syntax');
+
+  DeprecatedEachSyntax.prototype.detect = function(node) {
+    return astInfo.isBlockStatement(node) &&
+      node.path.original === 'each' &&
+      node.params.length > 1 &&
+      node.params[1].original === 'in';
+  };
+
+  DeprecatedEachSyntax.prototype.process = function(node) {
+    var params = node.params;
+    var singular = params[0].original;
+    var collection = params[2].original;
+
+    var actual = '{{#each ' + singular + ' in ' + collection + '}}';
+    var expected = '{{#each ' + collection + ' as |' + singular + '|}}';
+
+    var startLocation = calculateLocationDisplay(this.options.moduleName, node.loc && node.loc.start);
+
+    var message = [
+      'Deprecated {{#each}} usage at ' + startLocation,
+      'Actual: ' + actual,
+      'Expected (Rewrite the template to this): ' + expected,
+      'The `#each in` syntax was deprecated in 1.11 and removed in 2.0.',
+      'See the deprecation guide at ' + DEPRECATION_URL
+    ].join('\n');
+
+    this.log(message);
+  };
+
+  return DeprecatedEachSyntax;
+};
diff --git a/ext/plugins/index.js b/ext/plugins/index.js
index f30be36..11ce3b0 100644
--- a/ext/plugins/index.js
+++ b/ext/plugins/index.js
@@ -5,5 +5,6 @@ module.exports = {
   'block-indentation': require('./lint-block-indentation'),
   'html-comments': require('./lint-html-comments'),
   'triple-curlies': require('./lint-triple-curlies'),
-  'nested-interactive': require('./lint-nested-interactive')
+  'nested-interactive': require('./lint-nested-interactive'),
+  'deprecated-each-syntax': require('./deprecations/lint-deprecated-each-syntax')
 };


Test patch:
diff --git a/node-tests/unit/plugins/deprecations/lint-deprecated-each-syntax-test.js b/node-tests/unit/plugins/deprecations/lint-deprecated-each-syntax-test.js
new file mode 100644
index 0000000..c2bed13
--- /dev/null
+++ b/node-tests/unit/plugins/deprecations/lint-deprecated-each-syntax-test.js
@@ -0,0 +1,29 @@
+'use strict';
+
+var generateRuleTests = require('../../../helpers/rule-test-harness');
+
+var DEPRECATION_URL = 'http://emberjs.com/deprecations/v1.x/#toc_code-in-code-syntax-for-code-each-code';
+
+generateRuleTests({
+  name: 'deprecated-each-syntax',
+
+  good: [
+    {
+      template: '{{#each posts as |post|}}{{post.name}}{{/each}}'
+    }
+  ],
+
+  bad: [
+    {
+      template: '{{#each post in posts}}{{post.name}}{{/each}}',
+      message: [
+        "Deprecated {{#each}} usage at ('layout.hbs'@ L1:C0)",
+        'Actual: {{#each post in posts}}',
+        'Expected (Rewrite the template to this): ' + '{{#each posts as |post|}}',
+        'The `#each in` syntax was deprecated in 1.11 and removed in 2.0.',
+        'See the deprecation guide at ' + DEPRECATION_URL
+      ].join('\n')
+    }
+  ]
+});
+