Repository: rwjblue/ember-cli-template-lint
Pull request #68 (2016-04-07 11:40:05)

Support per-template configuration comments
Fixes https://github.com/rwjblue/ember-cli-template-lint/issues/67

We're no longer removing linting configuration html comments in individual plugins, this now happens as a final step in an `internal-remove-configuration-html-comments` plugin

/cc @rwjblue

GavinJoyce: I'm running this in production for Intercom. The linting is working fine, the `<!-- template-lint triple-curlies=false -->` aren't being removed from the output though.

Any ideas of how we could create some integration tests which test the actual output?
mixonic: ember-cli has some infrastructure for doing full acceptance tests- but there isn't any addon I know of that does a great job with acceptance testing :-/

This looks pretty good to me. Nudge @rwjblue 

Patch:
diff --git a/ext/helpers/ast-node-info.js b/ext/helpers/ast-node-info.js
new file mode 100644
index 0000000..c0444d9
--- /dev/null
+++ b/ext/helpers/ast-node-info.js
@@ -0,0 +1,13 @@
+'use strict';
+
+function AstNodeInfo() {}
+
+AstNodeInfo.isConfigurationHtmlComment = function(node) {
+  return node.type === 'CommentStatement' && node.value.trim().indexOf('template-lint ') === 0;
+};
+
+AstNodeInfo.isNonConfigurationHtmlComment = function(node) {
+  return node.type === 'CommentStatement' && node.value.trim().indexOf('template-lint ') !== 0;
+};
+
+module.exports = AstNodeInfo;
diff --git a/ext/plugins/base.js b/ext/plugins/base.js
index 611e8f4..b1aa082 100644
--- a/ext/plugins/base.js
+++ b/ext/plugins/base.js
@@ -41,8 +41,6 @@ module.exports = function(addonContext, name) {
         // 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);
         }
       }
     }
diff --git a/ext/plugins/index.js b/ext/plugins/index.js
index 09f084f..59ff7c5 100644
--- a/ext/plugins/index.js
+++ b/ext/plugins/index.js
@@ -4,5 +4,7 @@ module.exports = {
   'bare-strings': require('./lint-bare-strings'),
   'block-indentation': require('./lint-block-indentation'),
   'html-comments': require('./lint-html-comments'),
-  'triple-curlies': require('./lint-triple-curlies')
+  'triple-curlies': require('./lint-triple-curlies'),
+
+  'internal-remove-configuration-html-comments': require('./internal/remove-configuration-html-comments')
 };
diff --git a/ext/plugins/internal/lint-configuration-html-comments.js b/ext/plugins/internal/lint-configuration-html-comments.js
new file mode 100644
index 0000000..6f95434
--- /dev/null
+++ b/ext/plugins/internal/lint-configuration-html-comments.js
@@ -0,0 +1,23 @@
+'use strict';
+
+// this Babel plugin is used in the acceptance tests to ensure that there are
+// no configuration comments in the final output, such as:
+//   <!-- template-lint triple-curlies=false -->
+//   <!-- template-lint enabled=false -->
+
+var buildPlugin = require('../base');
+var AstNodeInfo = require('../../helpers/ast-node-info');
+
+module.exports = function(addonContext) {
+  var LintConfigurationHtmlComments = buildPlugin(addonContext, 'lint-configuration-html-comments');
+
+  LintConfigurationHtmlComments.prototype.detect = function(node) {
+    return AstNodeInfo.isConfigurationHtmlComment(node);
+  };
+
+  LintConfigurationHtmlComments.prototype.process = function(node) {
+    this.log('Html comment detected `<!--' + node.value + '-->`');
+  };
+
+  return LintConfigurationHtmlComments;
+};
diff --git a/ext/plugins/internal/remove-configuration-html-comments.js b/ext/plugins/internal/remove-configuration-html-comments.js
new file mode 100644
index 0000000..2b394f0
--- /dev/null
+++ b/ext/plugins/internal/remove-configuration-html-comments.js
@@ -0,0 +1,33 @@
+'use strict';
+
+// this Babel plugin removes configuration comments such as:
+//   <!-- template-lint triple-curlies=false -->
+//   <!-- template-lint enabled=false -->
+
+var AstNodeInfo = require('../../helpers/ast-node-info');
+
+module.exports = function() {
+  function RemoveConfigurationHtmlCommentsPlugin() {}
+
+  RemoveConfigurationHtmlCommentsPlugin.prototype.transform = function(ast) {
+    var walker = new this.syntax.Walker();
+    var bodyEntry;
+
+    walker.visit(ast, function(node) {
+      if (node.type === 'Program') {
+        for (var i = 0; i < node.body.length; i++) {
+          bodyEntry = node.body[i];
+
+          if(AstNodeInfo.isConfigurationHtmlComment(bodyEntry)) {
+            // remove the entry
+            node.body.splice(i, 1);
+          }
+        }
+      }
+    });
+
+    return ast;
+  };
+
+  return RemoveConfigurationHtmlCommentsPlugin;
+};
diff --git a/ext/plugins/lint-html-comments.js b/ext/plugins/lint-html-comments.js
index 37c0234..1335141 100644
--- a/ext/plugins/lint-html-comments.js
+++ b/ext/plugins/lint-html-comments.js
@@ -1,6 +1,7 @@
 'use strict';
 
 var calculateLocationDisplay = require('../helpers/calculate-location-display');
+var AstNodeInfo = require('../helpers/ast-node-info');
 var buildPlugin = require('./base');
 
 module.exports = function(addonContext) {
@@ -24,7 +25,7 @@ module.exports = function(addonContext) {
   };
 
   LogHtmlComments.prototype.detect = function(node) {
-    return node.type === 'CommentStatement';
+    return AstNodeInfo.isNonConfigurationHtmlComment(node);
   };
 
   LogHtmlComments.prototype.process = function(node) {


Test patch:
diff --git a/node-tests/helpers/rule-test-harness.js b/node-tests/helpers/rule-test-harness.js
index 7eb25cb..16b1608 100644
--- a/node-tests/helpers/rule-test-harness.js
+++ b/node-tests/helpers/rule-test-harness.js
@@ -10,7 +10,7 @@ module.exports = function(options) {
     var DISABLE_ALL = '<!-- template-lint disable=true -->';
     var DISABLE_ONE = '<!-- template-lint ' + options.name + '=false -->';
 
-    var addonContext,  messages, config;
+    var addonContext, messages, config;
 
     function compile(template) {
       _compile(template, {
diff --git a/node-tests/unit/plugins/internal/remove-configuration-html-comments-test.js b/node-tests/unit/plugins/internal/remove-configuration-html-comments-test.js
new file mode 100644
index 0000000..7158c74
--- /dev/null
+++ b/node-tests/unit/plugins/internal/remove-configuration-html-comments-test.js
@@ -0,0 +1,43 @@
+'use strict';
+
+var assert = require('assert');
+var _compile = require('htmlbars').compile;
+var plugins = require('../../../../ext/plugins');
+var lintConfigurationHtmlComments = require('../../../../ext/plugins/internal/lint-configuration-html-comments');
+
+describe('internal/remove-configuration-html-comments', function() {
+  var addonContext, messages;
+
+  function compile(template) {
+    _compile(template, {
+      moduleName: 'layout.hbs',
+      plugins: {
+        ast: [
+          plugins['internal-remove-configuration-html-comments'](addonContext),
+          lintConfigurationHtmlComments(addonContext)
+        ]
+      }
+    });
+  }
+
+  beforeEach(function() {
+    messages = [];
+
+    addonContext = {
+      logLintingError: function(pluginName, moduleName, message) {
+        messages.push(message);
+      },
+      loadConfig: function() {
+        return {};
+      }
+    };
+  });
+
+  it('should remove `template-lint` configuration html comments', function() {
+    compile('<!-- template-lint triple-curlies=false -->\n' +
+            '<!-- template-lint enable=false -->\n' +
+            '<div>hi Alex & Ben</div>');
+
+    assert.deepEqual(messages, [], '`template-lint` configuration html comments are removed');
+  });
+});
diff --git a/node-tests/unit/plugins/lint-bare-strings-test.js b/node-tests/unit/plugins/lint-bare-strings-test.js
index 0132198..08bec12 100644
--- a/node-tests/unit/plugins/lint-bare-strings-test.js
+++ b/node-tests/unit/plugins/lint-bare-strings-test.js
@@ -21,15 +21,11 @@ generateRuleTests({
       config: ['/', '"'],
       template: '{{t "foo"}} / "{{name}}"'
     },
-    {
-      template: '{{t "foo"}}'
-    },
-    {
-      template: '{{t "foo"}}, {{t "bar"}} ({{length}})'
-    },
-    {
-      template: '(),.&+-=*/#%!?:[]{}'
-    }
+    '{{t "foo"}}',
+    '{{t "foo"}}, {{t "bar"}} ({{length}})',
+    '(),.&+-=*/#%!?:[]{}',
+    '<!-- template-lint bare-strings=false -->',
+    '<!-- template-lint enabled=false -->'
   ],
 
   bad: [
diff --git a/node-tests/unit/plugins/lint-block-indentation-test.js b/node-tests/unit/plugins/lint-block-indentation-test.js
index 03a6e93..cfbc8b9 100644
--- a/node-tests/unit/plugins/lint-block-indentation-test.js
+++ b/node-tests/unit/plugins/lint-block-indentation-test.js
@@ -81,7 +81,9 @@ generateRuleTests({
         '<div>\n' +
         '\t<p>Hi!</p>\n' +
         '</div>'
-    }
+    },
+    '<!-- template-lint bare-strings=false -->',
+    '<!-- template-lint enabled=false -->'
   ],
 
   bad: [
diff --git a/node-tests/unit/plugins/lint-html-comments-test.js b/node-tests/unit/plugins/lint-html-comments-test.js
index 0b33dea..0c7c5e3 100644
--- a/node-tests/unit/plugins/lint-html-comments-test.js
+++ b/node-tests/unit/plugins/lint-html-comments-test.js
@@ -10,7 +10,8 @@ generateRuleTests({
   good: [
     '{{!-- comment here --}}',
     '{{!--comment here--}}',
-    '<!-- template-lint bare-strings=false -->'
+    '<!-- template-lint bare-strings=false -->',
+    '<!-- template-lint enabled=false -->'
   ],
 
   bad: [
diff --git a/node-tests/unit/plugins/lint-triple-curlies-test.js b/node-tests/unit/plugins/lint-triple-curlies-test.js
index 487c01d..fb16302 100644
--- a/node-tests/unit/plugins/lint-triple-curlies-test.js
+++ b/node-tests/unit/plugins/lint-triple-curlies-test.js
@@ -8,7 +8,9 @@ generateRuleTests({
   config: true,
 
   good: [
-    '{{foo}}'
+    '{{foo}}',
+    '<!-- template-lint bare-strings=false -->',
+    '<!-- template-lint enabled=false -->'
   ],
 
   bad: [