Repository: rwjblue/ember-cli-template-lint (js)

Issue:
Add general file level comment to disable in template.
Should allow ignoring a specific rule or all rules (ala `// jscs disable`)...

Pull request description:
Add ability to disable all rules or a subset of rules.
Syntax is:

```hbs
<!-- template-lint disable=true -->

{{! do bad things ;P }}
```

```hbs
<!-- template-lint triple-curlies=false -->

{{{foo}}}
```

Closes #17.

Patch:
diff --git a/README.md b/README.md
index d76c530..23a7e3e 100644
--- a/README.md
+++ b/README.md
@@ -42,7 +42,7 @@ module.exports = function(env) {
 }
 ```
 
-Plugins are included by default. You can turn off plugins by toggling them in a
+Rules are enabled by default. You can turn off specific rules by toggling them in a
 `.template-lintrc` file at the base of your project:
 
 ```javascript
@@ -51,8 +51,19 @@ module.exports = {
 }
 ```
 
-## Plugins
-Checkout the `ext/plugins/index.js` for a list of all linting plugins.
+It is also possible to disable specific rules (or all rules) in a template itself:
+
+```hbs
+{{! disable all rules for this template }}
+<!-- template-lint disable=true -->
+
+{{! disable specific rules for this template }}
+<!-- template-lint bare-strings=false -->
+```
+
+## Rules
+
+Checkout the `ext/plugins/index.js` for a list of all rules.
 
 ## Contributing
 
diff --git a/ext/plugins/base.js b/ext/plugins/base.js
index 955569a..ee6c163 100644
--- a/ext/plugins/base.js
+++ b/ext/plugins/base.js
@@ -8,15 +8,15 @@ module.exports = function(addonContext, name) {
   }
 
   BasePlugin.prototype.transform = function(ast) {
-    if (this.config === false) {
-      return ast;
-    }
-
     var pluginContext = this;
     var walker = new this.syntax.Walker();
 
     walker.visit(ast, function(node) {
-      if (pluginContext.detect(node)) {
+      pluginContext._processConfigStatement(node);
+
+      if (pluginContext.isDisabled()) {
+        // do nothing
+      } else if (pluginContext.detect(node)) {
         pluginContext.process(node);
       }
     });
@@ -24,6 +24,56 @@ module.exports = function(addonContext, name) {
     return ast;
   };
 
+  BasePlugin.prototype._processConfigStatement = function(node) {
+    var bodyEntry;
+
+    if (node.type === 'Program') {
+      for (var i = 0; i < node.body.length; i++) {
+        bodyEntry = node.body[i];
+
+        // process `<!-- template-lint foo=bar -->` comments
+        if (bodyEntry.type === 'CommentStatement' && bodyEntry.value.indexOf('template-lint') === 1) {
+          this._processConfigNode(bodyEntry);
+          // remove the entry
+          node.body.splice(i, 1);
+        }
+      }
+    }
+  };
+
+  BasePlugin.prototype._processConfigNode = function(node) {
+    var hashParts = node.value
+          .trim()
+          .slice(14)
+          .split(/\s+/);
+
+    var hash = hashParts.reduce(function(memo, part) {
+      var parts = part.split('=');
+
+      memo[parts[0]] = parts[1];
+
+      return memo;
+    }, {});
+
+    for (var key in hash) {
+      var value = hash[key];
+
+      // handle <!-- template-lint disabled=true -->
+      if (key === 'disable' && value === 'true') {
+        this.config = false;
+      }
+
+      // handle <!-- template-lint block-indentation=false -->
+      if (key === name && value === 'false') {
+        this.config = false;
+      }
+    }
+  };
+
+  BasePlugin.prototype.isDisabled = function() {
+    return this.config === false;
+  };
+
   BasePlugin.prototype.log = function(message) {
     addonContext.logLintingError(name, this.options.moduleName, message);
   };


Test patch:
diff --git a/node-tests/unit/plugins/lint-block-indentation-test.js b/node-tests/unit/plugins/lint-block-indentation-test.js
index 27f4c09..e205d27 100644
--- a/node-tests/unit/plugins/lint-block-indentation-test.js
+++ b/node-tests/unit/plugins/lint-block-indentation-test.js
@@ -5,6 +5,8 @@ var buildTemplateCompiler = require('../../helpers/template-compiler');
 var plugins = require('../../../ext/plugins');
 
 describe('Block indentation plugin', function() {
+  var DISABLE_ALL = '<!-- template-lint disable=true -->';
+  var DISABLE_ONE = '<!-- template-lint block-indentation=false -->';
   var BAD = '\n  {{#each cats as |dog|}}  {{/each}}';
   var GOOD = '\n  {{#each cats as |dog|}}\n  {{/each}}';
   var addonContext;
@@ -47,7 +49,7 @@ describe('Block indentation plugin', function() {
     assert.deepEqual(messages, []);
   });
 
-  it('rule can be disabled', function() {
+  it('rule can be disabled via config', function() {
     config['block-indentation'] = false;
     templateCompiler.registerPlugin('ast', plugins['block-indentation'](addonContext));
     templateCompiler.precompile(BAD, {
@@ -56,4 +58,22 @@ describe('Block indentation plugin', function() {
 
     assert.deepEqual(messages, []);
   });
+
+  it('rule can be disabled via inline comment - single rule', function() {
+    templateCompiler.registerPlugin('ast', plugins['block-indentation'](addonContext));
+    templateCompiler.precompile(DISABLE_ONE + '\n' + BAD, {
+      moduleName: 'layout.hbs'
+    });
+
+    assert.deepEqual(messages, []);
+  });
+
+  it('rule can be disabled via inline comment - all rules', function() {
+    templateCompiler.registerPlugin('ast', plugins['block-indentation'](addonContext));
+    templateCompiler.precompile(DISABLE_ALL + '\n' + BAD, {
+      moduleName: 'layout.hbs'
+    });
+
+    assert.deepEqual(messages, []);
+  });
 });
diff --git a/node-tests/unit/plugins/lint-triple-curlies-test.js b/node-tests/unit/plugins/lint-triple-curlies-test.js
index e0b7019..ad8dd7f 100644
--- a/node-tests/unit/plugins/lint-triple-curlies-test.js
+++ b/node-tests/unit/plugins/lint-triple-curlies-test.js
@@ -5,6 +5,8 @@ var buildTemplateCompiler = require('../../helpers/template-compiler');
 var plugins = require('../../../ext/plugins');
 
 describe('triple curlies', function() {
+  var DISABLE_ALL = '<!-- template-lint disable=true -->';
+  var DISABLE_ONE = '<!-- template-lint triple-curlies=false -->';
   var GOOD = '{{foo}}';
   var BAD = '\n {{{foo}}}';
   var addonContext;
@@ -56,4 +58,22 @@ describe('triple curlies', function() {
 
     assert.deepEqual(messages, []);
   });
+
+  it('rule can be disabled via inline comment - single rule', function() {
+    templateCompiler.registerPlugin('ast', plugins['triple-curlies'](addonContext));
+    templateCompiler.precompile(DISABLE_ONE + '\n' + BAD, {
+      moduleName: 'layout.hbs'
+    });
+
+    assert.deepEqual(messages, []);
+  });
+
+  it('rule can be disabled via inline comment - all rules', function() {
+    templateCompiler.registerPlugin('ast', plugins['triple-curlies'](addonContext));
+    templateCompiler.precompile(DISABLE_ALL + '\n' + BAD, {
+      moduleName: 'layout.hbs'
+    });
+
+    assert.deepEqual(messages, []);
+  });
 });