diff --git a/docs/rules/no-comment-textnodes.md b/docs/rules/no-comment-textnodes.md
new file mode 100644
index 0000000000..22e73b16b3
--- /dev/null
+++ b/docs/rules/no-comment-textnodes.md
@@ -0,0 +1,68 @@
+# Prevent comments from being inserted as text nodes (no-comment-textnodes)
+
+This rule prevents comment strings (e.g. beginning with `//` or `/*`) from being accidentally
+injected as a text node in JSX statements.
+
+## Rule Details
+
+The following patterns are considered warnings:
+
+```js
+var Hello = React.createClass({
+ render: function() {
+ return (
+
;
+ }
+});
+```
+
+## Legitimate uses
+
+It's possible you may want to legitimately output comment start characters (`//` or `/*`)
+in a JSX text node. In which case, you can do the following:
+
+```js
+var Hello = React.createClass({
+ render: function() {
+ return (
+
{'/* This will be output as a text node */'}
+ );
+ }
+});
+```
diff --git a/index.js b/index.js
index 1969347591..ffe1304a5b 100644
--- a/index.js
+++ b/index.js
@@ -8,6 +8,7 @@ module.exports = {
'display-name': require('./lib/rules/display-name'),
'wrap-multilines': require('./lib/rules/wrap-multilines'),
'self-closing-comp': require('./lib/rules/self-closing-comp'),
+ 'no-comment-textnodes': require('./lib/rules/no-comment-textnodes'),
'no-danger': require('./lib/rules/no-danger'),
'no-set-state': require('./lib/rules/no-set-state'),
'no-is-mounted': require('./lib/rules/no-is-mounted'),
diff --git a/lib/rules/no-comment-textnodes.js b/lib/rules/no-comment-textnodes.js
new file mode 100644
index 0000000000..7a3bfc5895
--- /dev/null
+++ b/lib/rules/no-comment-textnodes.js
@@ -0,0 +1,38 @@
+/**
+ * @fileoverview Comments inside children section of tag should be placed inside braces.
+ * @author Ben Vinegar
+ */
+'use strict';
+
+// ------------------------------------------------------------------------------
+// Rule Definition
+// ------------------------------------------------------------------------------
+
+module.exports = function(context) {
+ function reportLiteralNode(node) {
+ context.report(node, 'Comments inside children section of tag should be placed inside braces');
+ }
+
+ // --------------------------------------------------------------------------
+ // Public
+ // --------------------------------------------------------------------------
+
+ return {
+ Literal: function(node) {
+ if (/\s*\/(\/|\*)/.test(node.value)) {
+ // inside component, e.g.
literal
+ if (node.parent.type !== 'JSXAttribute' &&
+ node.parent.type !== 'JSXExpressionContainer' &&
+ node.parent.type.indexOf('JSX') !== -1) {
+ reportLiteralNode(node);
+ }
+ }
+ }
+ };
+};
+
+module.exports.schema = [{
+ type: 'object',
+ properties: {},
+ additionalProperties: false
+}];
diff --git a/tests/lib/rules/no-comment-textnodes.js b/tests/lib/rules/no-comment-textnodes.js
new file mode 100644
index 0000000000..fcfd78d6a7
--- /dev/null
+++ b/tests/lib/rules/no-comment-textnodes.js
@@ -0,0 +1,204 @@
+/**
+ * @fileoverview Tests for no-comment-textnodes
+ * @author Ben Vinegar
+ */
+'use strict';
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+var rule = require('../../../lib/rules/no-comment-textnodes');
+var RuleTester = require('eslint').RuleTester;
+
+// ------------------------------------------------------------------------------
+// Tests
+// ------------------------------------------------------------------------------
+
+var ruleTester = new RuleTester();
+ruleTester.run('jsx-needs-i18n', rule, {
+
+ valid: [
+ {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (',
+ '
',
+ ' {/* valid */}',
+ '
',
+ ' );',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ }, {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (
{/* valid */}
);',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ }, {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' const bar = (
{/* valid */}
);',
+ ' return bar;',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ }, {
+ code: [
+ 'var Hello = React.createClass({',
+ ' foo: (
{/* valid */}
),',
+ ' render() {',
+ ' return this.foo;',
+ ' },',
+ '});'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ }, {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (',
+ '
',
+ ' {/* valid */}',
+ ' {/* valid 2 */}',
+ ' {/* valid 3 */}',
+ '
',
+ ' );',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ }, {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (',
+ '
',
+ '
',
+ ' );',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ }, {
+ code: [
+ 'var foo = require(\'foo\');'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ }, {
+ code: [
+ '
',
+ ' {/* valid */}',
+ ''
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ },
+
+ // inside element declarations
+ {
+ code: [
+ '
'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ },
+ {
+ code: [
+ ''
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint'
+ }
+ ],
+
+ invalid: [
+ {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (// invalid
);',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint',
+ errors: [{message: 'Comments inside children section of tag should be placed inside braces'}]
+ }, {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (/* invalid */
);',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint',
+ errors: [{message: 'Comments inside children section of tag should be placed inside braces'}]
+ }, {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (',
+ ' ',
+ ' // invalid',
+ '
',
+ ' );',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint',
+ errors: [{message: 'Comments inside children section of tag should be placed inside braces'}]
+ }, {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (',
+ ' ',
+ ' asdjfl',
+ ' /* invalid */',
+ ' foo',
+ '
',
+ ' );',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint',
+ errors: [{message: 'Comments inside children section of tag should be placed inside braces'}]
+ }, {
+ code: [
+ 'class Comp1 extends Component {',
+ ' render() {',
+ ' return (',
+ ' ',
+ ' {\'asdjfl\'}',
+ ' // invalid',
+ ' {\'foo\'}',
+ '
',
+ ' );',
+ ' }',
+ '}'
+ ].join('\n'),
+ args: [1],
+ parser: 'babel-eslint',
+ errors: [{message: 'Comments inside children section of tag should be placed inside braces'}]
+ }
+ ]
+});