Repository: yannickcr/eslint-plugin-react
Pull request #1485 (2017-10-17 15:38:13)

Fix `boolean-prop-naming` with Object.spread syntax
There is an issue where using Object.spread syntax with this rule causes Eslint to break as it attempts to look for `node.value.property` in a spread object. We avoid validating spread nodes by checking for the `ExperimentalSpreadProperty` type.

Reopened #1482 (github wasn't showing new commit) @ljharb 


Patch:
diff --git a/docs/rules/jsx-curly-brace-presence.md b/docs/rules/jsx-curly-brace-presence.md
index 44eb5657..b4e27a2b 100644
--- a/docs/rules/jsx-curly-brace-presence.md
+++ b/docs/rules/jsx-curly-brace-presence.md
@@ -122,7 +122,7 @@ will be warned and fixed to:
 <App prop="Hello world">Hello world</App>;
 ```
 
-* If the rule is set to enforce curly braces and the strings have quotes, it will be fixed with double quotes for JSX children and the normal way for JSX attributes. Also, double quotes will be escaped in the fix.
+* If the rule is set to enforce curly braces and the strings have quotes, it will be fixed with double quotes for JSX children and the normal way for JSX attributes.
 
 For example:
 
@@ -137,14 +137,12 @@ will warned and fixed to:
 <App prop={"Hello \"foo\" world"}>{"Hello 'foo' \"bar\" world"}</App>;
 ```
 
-* If the rule is set to get rid of unnecessary curly braces(JSX expression) and there are characters that need to be escaped in its JSX form, such as quote characters, [forbidden JSX text characters](https://facebook.github.io/jsx/), escaped characters and anything that looks like HTML entity names, the code will not be warned because the fix may make the code less readable.
+* If the rule is set to get rid of unnecessary curly braces and the strings have escaped characters, it will not warn or fix for JSX children because JSX expressions are necessary in this case. For instance:
 
 The following pattern will not be given a warning even if `'never'` is passed.
 
 ```jsx
-<Color text={"\u00a0"} />
 <App>{"Hello \u00b7 world"}</App>;
-<style type="text/css">{'.main { margin-top: 0; }'}</style>;
 ```
 
 ## When Not To Use It
diff --git a/lib/rules/boolean-prop-naming.js b/lib/rules/boolean-prop-naming.js
index c9baaa70..8a9a0076 100644
--- a/lib/rules/boolean-prop-naming.js
+++ b/lib/rules/boolean-prop-naming.js
@@ -85,6 +85,11 @@ module.exports = {
      * @param {Object} node The node we're getting the name of
      */
     function getPropKey(node) {
+      // Check for `ExperimentalSpreadProperty` so we can skip validation of those fields.
+      // Otherwise it will look for `node.value.property` which doesn't exist and breaks Eslint.
+      if (node.type === 'ExperimentalSpreadProperty') {
+        return null;
+      }
       if (node.value.property) {
         return node.value.property.name;
       }
diff --git a/lib/rules/jsx-curly-brace-presence.js b/lib/rules/jsx-curly-brace-presence.js
index ecb95767..51ef422b 100644
--- a/lib/rules/jsx-curly-brace-presence.js
+++ b/lib/rules/jsx-curly-brace-presence.js
@@ -1,7 +1,6 @@
 /**
  * @fileoverview Enforce curly braces or disallow unnecessary curly brace in JSX
  * @author Jacky Ho
- * @author Simon Lydell
  */
 'use strict';
 
@@ -60,45 +59,18 @@ module.exports = {
       {props: ruleOptions, children: ruleOptions} :
       Object.assign({}, DEFAULT_CONFIG, ruleOptions);
 
-    function containsLineTerminators(rawStringValue) {
-      return /[\n\r\u2028\u2029]/.test(rawStringValue);
-    }
-
-    function containsBackslash(rawStringValue) {
+    function containsBackslashForEscaping(rawStringValue) {
       return rawStringValue.includes('\\');
     }
 
-    function containsHTMLEntity(rawStringValue) {
-      return /&[A-Za-z\d#]+;/.test(rawStringValue);
-    }
-
-    function containsDisallowedJSXTextChars(rawStringValue) {
-      return /[{<>}]/.test(rawStringValue);
-    }
-
-    function containsQuoteCharacters(value) {
-      return /['"]/.test(value);
-    }
-
     function escapeDoubleQuotes(rawStringValue) {
       return rawStringValue.replace(/\\"/g, '"').replace(/"/g, '\\"');
     }
 
-    function escapeBackslashes(rawStringValue) {
-      return rawStringValue.replace(/\\/g, '\\\\');
-    }
-
-    function needToEscapeCharacterForJSX(raw) {
-      return (
-        containsBackslash(raw) ||
-        containsHTMLEntity(raw) ||
-        containsDisallowedJSXTextChars(raw)
-      );
-    }
-
     /**
      * Report and fix an unnecessary curly brace violation on a node
      * @param {ASTNode} node - The AST node with an unnecessary JSX expression
+     * @param {String} text - The text to replace the unnecessary JSX expression
      */
     function reportUnnecessaryCurly(JSXExpressionNode) {
       context.report({
@@ -111,10 +83,11 @@ module.exports = {
 
           let textToReplace;
           if (parentType === 'JSXAttribute') {
-            textToReplace = `"${expressionType === 'TemplateLiteral' ?
-              expression.quasis[0].value.raw :
-              expression.raw.substring(1, expression.raw.length - 1)
-            }"`;
+            textToReplace = `"${escapeDoubleQuotes(
+              expressionType === 'TemplateLiteral' ?
+                expression.quasis[0].value.raw :
+                expression.raw.substring(1, expression.raw.length - 1)
+            )}"`;
           } else {
             textToReplace = expressionType === 'TemplateLiteral' ?
               expression.quasis[0].value.cooked : expression.value;
@@ -130,20 +103,10 @@ module.exports = {
         node: literalNode,
         message: 'Need to wrap this literal in a JSX expression.',
         fix: function(fixer) {
-          // If a HTML entity name is found, bail out because it can be fixed
-          // by either using the real character or the unicode equivalent.
-          // If it contains any line terminator character, bail out as well.
-          if (
-            containsHTMLEntity(literalNode.raw) ||
-            containsLineTerminators(literalNode.raw)
-          ) {
-            return null;
-          }
-
           const expression = literalNode.parent.type === 'JSXAttribute' ?
-            `{"${escapeDoubleQuotes(escapeBackslashes(
+            `{"${escapeDoubleQuotes(
               literalNode.raw.substring(1, literalNode.raw.length - 1)
-            ))}"}` :
+            )}"}` :
             `{${JSON.stringify(literalNode.value)}}`;
 
           return fixer.replaceText(literalNode, expression);
@@ -151,9 +114,6 @@ module.exports = {
       });
     }
 
-    // Bail out if there is any character that needs to be escaped in JSX
-    // because escaping decreases readiblity and the original code may be more
-    // readible anyway or intentional for other specific reasons
     function lintUnnecessaryCurly(JSXExpressionNode) {
       const expression = JSXExpressionNode.expression;
       const expressionType = expression.type;
@@ -161,20 +121,16 @@ module.exports = {
 
       if (
         expressionType === 'Literal' &&
-          typeof expression.value === 'string' &&
-          !needToEscapeCharacterForJSX(expression.raw) && (
-          parentType === 'JSXElement' ||
-          !containsQuoteCharacters(expression.value)
-        )
+          typeof expression.value === 'string' && (
+          parentType === 'JSXAttribute' ||
+          !containsBackslashForEscaping(expression.raw))
       ) {
         reportUnnecessaryCurly(JSXExpressionNode);
       } else if (
         expressionType === 'TemplateLiteral' &&
-          expression.expressions.length === 0 &&
-          !needToEscapeCharacterForJSX(expression.quasis[0].value.raw) && (
-          parentType === 'JSXElement' ||
-          !containsQuoteCharacters(expression.quasis[0].value.cooked)
-        )
+          expression.expressions.length === 0 && (
+          parentType === 'JSXAttribute' ||
+          !containsBackslashForEscaping(expression.quasis[0].value.raw))
       ) {
         reportUnnecessaryCurly(JSXExpressionNode);
       }
@@ -214,13 +170,17 @@ module.exports = {
 
     return {
       JSXExpressionContainer: node => {
-        if (shouldCheckForUnnecessaryCurly(node.parent, userConfig)) {
+        const parent = node.parent;
+
+        if (shouldCheckForUnnecessaryCurly(parent, userConfig)) {
           lintUnnecessaryCurly(node);
         }
       },
 
       Literal: node => {
-        if (shouldCheckForMissingCurly(node.parent.type, userConfig)) {
+        const parentType = node.parent.type;
+
+        if (shouldCheckForMissingCurly(parentType, userConfig)) {
           reportMissingCurly(node);
         }
       }


Test patch:
diff --git a/tests/lib/rules/boolean-prop-naming.js b/tests/lib/rules/boolean-prop-naming.js
index 57320c52..bbaf6e2d 100644
--- a/tests/lib/rules/boolean-prop-naming.js
+++ b/tests/lib/rules/boolean-prop-naming.js
@@ -17,6 +17,7 @@ const parserOptions = {
   ecmaVersion: 6,
   sourceType: 'module',
   ecmaFeatures: {
+    experimentalObjectRestSpread: true,
     jsx: true
   }
 };
@@ -145,6 +146,31 @@ ruleTester.run('boolean-prop-naming', rule, {
       rule: '^is[A-Z]([A-Za-z0-9]?)+'
     }],
     parser: 'babel-eslint'
+  }, {
+    // ES6 components with static class properties and Object.spread syntax in PropTypes
+    code: `
+      const spreadProps = { aSpreadProp: PropTypes.string };
+      class Hello extends React.Component {
+        static propTypes = {isSomething: PropTypes.bool, ...spreadProps};
+        render () { return <div />; }
+      }
+    `,
+    options: [{
+      rule: '^is[A-Z]([A-Za-z0-9]?)+'
+    }],
+    parser: 'babel-eslint'
+  }, {
+    // ES6 components as Component with boolean PropTypes and Object.spread syntax in PropTypes
+    code: `
+      const spreadProps = { aSpreadProp: PropTypes.string };
+      class Hello extends Component {
+        render () { return <div />; }
+      }
+      Hello.propTypes = {isSomething: PropTypes.bool, ...spreadProps}
+    `,
+    options: [{
+      rule: '^is[A-Z]([A-Za-z0-9]?)+'
+    }]
   }, {
     // ES6 components with static class properties and React.PropTypes
     code: `
@@ -361,6 +387,37 @@ ruleTester.run('boolean-prop-naming', rule, {
     errors: [{
       message: 'Prop name (something) doesn\'t match rule (^is[A-Z]([A-Za-z0-9]?)+)'
     }]
+  }, {
+    // ES6 components as React.Component with non-boolean PropTypes and Object.spread syntax
+    code: `
+      const spreadProps = { aSpreadProp: PropTypes.string };
+      class Hello extends Component {
+        render () { return <div />; }
+      }
+      Hello.propTypes = {something: PropTypes.bool, ...spreadProps}
+    `,
+    options: [{
+      rule: '^is[A-Z]([A-Za-z0-9]?)+'
+    }],
+    errors: [{
+      message: 'Prop name (something) doesn\'t match rule (^is[A-Z]([A-Za-z0-9]?)+)'
+    }]
+  }, {
+    // ES6 components as React.Component with static class property, non-boolean PropTypes, and Object.spread syntax
+    code: `
+      const spreadProps = { aSpreadProp: PropTypes.string };
+      class Hello extends React.Component {
+        static propTypes = {something: PropTypes.bool, ...spreadProps};
+        render () { return <div />; }
+      }
+    `,
+    options: [{
+      rule: '^is[A-Z]([A-Za-z0-9]?)+'
+    }],
+    parser: 'babel-eslint',
+    errors: [{
+      message: 'Prop name (something) doesn\'t match rule (^is[A-Z]([A-Za-z0-9]?)+)'
+    }]
   }, {
     // ES6 components as React.Component with non-boolean PropTypes
     code: `
diff --git a/tests/lib/rules/jsx-curly-brace-presence.js b/tests/lib/rules/jsx-curly-brace-presence.js
index 959bf079..1ae02da4 100644
--- a/tests/lib/rules/jsx-curly-brace-presence.js
+++ b/tests/lib/rules/jsx-curly-brace-presence.js
@@ -4,8 +4,6 @@
  */
 'use strict';
 
-/* eslint-disable quotes */ // For better readability on tests involving quotes
-
 // ------------------------------------------------------------------------------
 // Requirements
 // ------------------------------------------------------------------------------
@@ -73,7 +71,7 @@ ruleTester.run('jsx-curly-brace-presence', rule, {
       code: '<App>{"foo"}{<Component>bar</Component>}</App>'
     },
     {
-      code: `<App prop='bar'>foo</App>`
+      code: '<App prop=\'bar\'>foo</App>'
     },
     {
       code: '<App prop={true}>foo</App>'
@@ -82,14 +80,14 @@ ruleTester.run('jsx-curly-brace-presence', rule, {
       code: '<App prop>foo</App>'
     },
     {
-      code: `<App prop='bar'>{'foo \\n bar'}</App>`
+      code: '<App prop=\'bar\'>{\'foo \\n bar\'}</App>'
     },
     {
-      code: `<MyComponent prop='bar'>foo</MyComponent>`,
+      code: '<MyComponent prop=\'bar\'>foo</MyComponent>',
       options: [{props: 'never'}]
     },
     {
-      code: `<MyComponent prop="bar">foo</MyComponent>`,
+      code: '<MyComponent prop=\"bar\">foo</MyComponent>',
       options: [{props: 'never'}]
     },
     {
@@ -101,31 +99,31 @@ ruleTester.run('jsx-curly-brace-presence', rule, {
       options: [{children: 'never'}]
     },
     {
-      code: `<App>{"foo 'bar' \\"foo\\" bar"}</App>`,
+      code: '<App>{\"foo \'bar\' \\\"foo\\\" bar\"}</App>',
       options: [{children: 'never'}]
     },
     {
-      code: `<MyComponent prop={'bar'}>foo</MyComponent>`,
+      code: '<MyComponent prop={\'bar\'}>foo</MyComponent>',
       options: [{props: 'always'}]
     },
     {
-      code: `<MyComponent>{'foo'}</MyComponent>`,
+      code: '<MyComponent>{\'foo\'}</MyComponent>',
       options: [{children: 'always'}]
     },
     {
-      code: `<MyComponent prop={"bar"}>foo</MyComponent>`,
+      code: '<MyComponent prop={\"bar\"}>foo</MyComponent>',
       options: [{props: 'always'}]
     },
     {
-      code: `<MyComponent>{"foo"}</MyComponent>`,
+      code: '<MyComponent>{\"foo\"}</MyComponent>',
       options: [{children: 'always'}]
     },
     {
-      code: `<MyComponent>{'foo'}</MyComponent>`,
+      code: '<MyComponent>{\'foo\'}</MyComponent>',
       options: [{children: 'ignore'}]
     },
     {
-      code: `<MyComponent prop={'bar'}>foo</MyComponent>`,
+      code: '<MyComponent prop={\'bar\'}>foo</MyComponent>',
       options: [{props: 'ignore'}]
     },
     {
@@ -133,91 +131,87 @@ ruleTester.run('jsx-curly-brace-presence', rule, {
       options: [{children: 'ignore'}]
     },
     {
-      code: `<MyComponent prop='bar'>foo</MyComponent>`,
+      code: '<MyComponent prop=\'bar\'>foo</MyComponent>',
       options: [{props: 'ignore'}]
     },
     {
-      code: `<MyComponent prop="bar">foo</MyComponent>`,
+      code: '<MyComponent prop=\"bar\">foo</MyComponent>',
       options: [{props: 'ignore'}]
     },
     {
-      code: `<MyComponent prop='bar'>{'foo'}</MyComponent>`,
+      code: '<MyComponent prop=\'bar\'>{\'foo\'}</MyComponent>',
       options: [{children: 'always', props: 'never'}]
     },
     {
-      code: `<MyComponent prop={'bar'}>foo</MyComponent>`,
+      code: '<MyComponent prop={\'bar\'}>foo</MyComponent>',
       options: [{children: 'never', props: 'always'}]
     },
     {
-      code: `<MyComponent prop={'bar'}>{'foo'}</MyComponent>`,
+      code: '<MyComponent prop={\'bar\'}>{\'foo\'}</MyComponent>',
       options: ['always']
     },
     {
-      code: `<MyComponent prop={"bar"}>{"foo"}</MyComponent>`,
+      code: '<MyComponent prop={\"bar\"}>{\"foo\"}</MyComponent>',
       options: ['always']
     },
     {
-      code: `<MyComponent prop={"bar"} attr={'foo'} />`,
+      code: '<MyComponent prop={\"bar\"} attr={\'foo\'} />',
       options: ['always']
     },
     {
-      code: `<MyComponent prop="bar" attr='foo' />`,
+      code: '<MyComponent prop=\"bar\" attr=\'foo\' />',
       options: ['never']
     },
     {
-      code: `<MyComponent prop='bar'>foo</MyComponent>`,
+      code: '<MyComponent prop=\'bar\'>foo</MyComponent>',
       options: ['never']
     },
     {
       code: '<MyComponent prop={`bar ${word} foo`}>{`foo ${word}`}</MyComponent>',
       options: ['never']
-    },
-    {
-      code: '<MyComponent>{"div { margin-top: 0; }"}</MyComponent>',
-      options: ['never']
-    },
-    {
-      code: '<MyComponent>{"<Foo />"}</MyComponent>',
-      options: ['never']
-    },
-    {
-      code: '<MyComponent prop={"{ style: true }"}>bar</MyComponent>',
-      options: ['never']
-    },
+    }
+  ],
+
+  invalid: [
     {
-      code: '<MyComponent prop={"< style: true >"}>foo</MyComponent>',
-      options: ['never']
+      code: '<App prop={`foo`} />',
+      output: '<App prop="foo" />',
+      options: [{props: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: '<MyComponent prop={"Hello \\u1026 world"}>bar</MyComponent>',
-      options: ['never']
+      code: '<App prop={\'foo \\u00b7 bar\'}>foo</App>',
+      output: '<App prop=\"foo \\u00b7 bar\">foo</App>',
+      options: [{props: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: '<MyComponent>{"Hello \\u1026 world"}</MyComponent>',
-      options: ['never']
+      code: '<App prop={`foo \\n bar`}>foo</App>',
+      output: '<App prop="foo \\n bar">foo</App>',
+      options: [{props: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: '<MyComponent prop={"Hello &middot; world"}>bar</MyComponent>',
-      options: ['never']
+      code: '<App prop={`foo \\u00b7 bar`}>foo</App>',
+      output: '<App prop="foo \\u00b7 bar">foo</App>',
+      options: [{props: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: '<MyComponent>{"Hello &middot; world"}</MyComponent>',
-      options: ['never']
+      code: '<App prop={`foo \\\'foo\\\' bar`}>foo</App>',
+      output: '<App prop="foo \\\'foo\\\' bar">foo</App>',
+      options: [{props: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: '<MyComponent>{"Hello \\n world"}</MyComponent>',
-      options: ['never']
+      code: '<App prop={`foo \\\"foo\\\" bar`}>foo</App>',
+      output: '<App prop="foo \\\"foo\\\" bar">foo</App>',
+      options: [{props: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: ['<a a={"start\\', '\\', 'end"}/>'].join('/n'),
-      options: ['never']
-    }
-  ],
-
-  invalid: [
-    {
-      code: '<App prop={`foo`} />',
-      output: '<App prop="foo" />',
+      code: '<App prop={`foo "foo" bar`}>foo</App>',
+      output: '<App prop="foo \\\"foo\\\" bar">foo</App>',
       options: [{props: 'never'}],
       errors: [{message: unnecessaryCurlyMessage}]
     },
@@ -234,204 +228,166 @@ ruleTester.run('jsx-curly-brace-presence', rule, {
       errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: `<MyComponent>{'foo'}</MyComponent>`,
+      code: '<App>{`foo "foo" bar`}</App>',
+      output: '<App>foo "foo" bar</App>',
+      options: [{children: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
+    },
+    {
+      code: '<MyComponent>{\'foo\'}</MyComponent>',
       output: '<MyComponent>foo</MyComponent>',
       errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: `<MyComponent prop={'bar'}>foo</MyComponent>`,
-      output: `<MyComponent prop="bar">foo</MyComponent>`,
+      code: '<MyComponent prop={\'bar\'}>foo</MyComponent>',
+      output: '<MyComponent prop=\"bar\">foo</MyComponent>',
       errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: `<MyComponent>{'foo'}</MyComponent>`,
+      code: '<MyComponent>{\'foo\'}</MyComponent>',
       output: '<MyComponent>foo</MyComponent>',
       options: [{children: 'never'}],
       errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: `<MyComponent prop={'bar'}>foo</MyComponent>`,
-      output: '<MyComponent prop="bar">foo</MyComponent>',
+      code: '<MyComponent prop={\'bar\'}>foo</MyComponent>',
+      output: '<MyComponent prop=\"bar\">foo</MyComponent>',
       options: [{props: 'never'}],
       errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: `<MyComponent prop='bar'>foo</MyComponent>`,
-      output: '<MyComponent prop={"bar"}>foo</MyComponent>',
-      options: [{props: 'always'}],
-      errors: [{message: missingCurlyMessage}]
+      code: '<MyComponent prop={\"bar \'foo\' \"}>foo</MyComponent>',
+      output: '<MyComponent prop=\"bar \'foo\' \">foo</MyComponent>',
+      options: [{props: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: `<MyComponent prop="foo 'bar'">foo</MyComponent>`,
-      output: `<MyComponent prop={"foo 'bar'"}>foo</MyComponent>`,
-      options: [{props: 'always'}],
-      errors: [{message: missingCurlyMessage}]
+      code: '<MyComponent prop={\'bar \"foo\" \'}>foo</MyComponent>',
+      output: '<MyComponent prop=\"bar \\\"foo\\\" \">foo</MyComponent>',
+      options: [{props: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
     },
     {
-      code: `<MyComponent prop='foo "bar"'>foo</MyComponent>`,
-      output: `<MyComponent prop={"foo \\"bar\\""}>foo</MyComponent>`,
+      code: '<MyComponent prop=\'bar\'>foo</MyComponent>',
+      output: '<MyComponent prop={\"bar\"}>foo</MyComponent>',
       options: [{props: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
-      code: `<MyComponent prop="foo 'bar'">foo</MyComponent>`,
-      output: `<MyComponent prop={"foo 'bar'"}>foo</MyComponent>`,
+      code: '<MyComponent prop=\"foo \'bar\'\">foo</MyComponent>',
+      output: '<MyComponent prop={\"foo \'bar\'\"}>foo</MyComponent>',
       options: [{props: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
-      code: '<MyComponent>foo bar </MyComponent>',
-      output: `<MyComponent>{"foo bar "}</MyComponent>`,
-      options: [{children: 'always'}],
+      code: '<MyComponent prop=\'foo "bar"\'>foo</MyComponent>',
+      output: '<MyComponent prop={\"foo \\\"bar\\\"\"}>foo</MyComponent>',
+      options: [{props: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
-      code: `<MyComponent prop="foo 'bar' \\n ">foo</MyComponent>`,
-      output: `<MyComponent prop={"foo 'bar' \\\\n "}>foo</MyComponent>`,
+      code: '<MyComponent prop=\"foo \'bar\'\">foo</MyComponent>',
+      output: '<MyComponent prop={\"foo \'bar\'\"}>foo</MyComponent>',
       options: [{props: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
-      code: '<MyComponent>foo bar \\r </MyComponent>',
-      output: '<MyComponent>{"foo bar \\\\r "}</MyComponent>',
+      code: '<MyComponent>foo bar </MyComponent>',
+      output: '<MyComponent>{\"foo bar \"}</MyComponent>',
       options: [{children: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
-      code: `<MyComponent>foo bar 'foo'</MyComponent>`,
-      output: `<MyComponent>{"foo bar 'foo'"}</MyComponent>`,
+      code: '<MyComponent>foo bar \'foo\'</MyComponent>',
+      output: '<MyComponent>{\"foo bar \'foo\'\"}</MyComponent>',
       options: [{children: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
-      code: '<MyComponent>foo bar "foo"</MyComponent>',
-      output: '<MyComponent>{"foo bar \\"foo\\""}</MyComponent>',
+      code: '<MyComponent>foo bar \"foo\"</MyComponent>',
+      output: '<MyComponent>{\"foo bar \\\"foo\\\"\"}</MyComponent>',
       options: [{children: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
       code: '<MyComponent>foo bar <App/></MyComponent>',
-      output: '<MyComponent>{"foo bar "}<App/></MyComponent>',
-      options: [{children: 'always'}],
-      errors: [{message: missingCurlyMessage}]
-    },
-    {
-      code: '<MyComponent>foo \\n bar</MyComponent>',
-      output: '<MyComponent>{"foo \\\\n bar"}</MyComponent>',
+      output: '<MyComponent>{\"foo bar \"}<App/></MyComponent>',
       options: [{children: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
-      code: '<MyComponent>foo \\u1234 bar</MyComponent>',
-      output: '<MyComponent>{"foo \\\\u1234 bar"}</MyComponent>',
+      code: '<MyComponent>foo\\nbar</MyComponent>',
+      output: '<MyComponent>{\"foo\\\\nbar\"}</MyComponent>',
       options: [{children: 'always'}],
       errors: [{message: missingCurlyMessage}]
     },
     {
-      code: `<MyComponent prop='foo \\u1234 bar' />`,
-      output: '<MyComponent prop={"foo \\\\u1234 bar"} />',
-      options: [{props: 'always'}],
-      errors: [{message: missingCurlyMessage}]
-    },
-    {
-      code: `<MyComponent prop={'bar'}>{'foo'}</MyComponent>`,
-      output: '<MyComponent prop="bar">foo</MyComponent>',
+      code: '<MyComponent prop={\'bar\'}>{\'foo\'}</MyComponent>',
+      output: '<MyComponent prop=\"bar\">foo</MyComponent>',
       options: ['never'],
       errors: [
         {message: unnecessaryCurlyMessage}, {message: unnecessaryCurlyMessage}
       ]
     },
     {
-      code: `<MyComponent prop='bar'>foo</MyComponent>`,
-      output: '<MyComponent prop={"bar"}>{"foo"}</MyComponent>',
+      code: '<MyComponent prop=\'bar\'>foo</MyComponent>',
+      output: '<MyComponent prop={\"bar\"}>{\"foo\"}</MyComponent>',
       options: ['always'],
       errors: [
         {message: missingCurlyMessage}, {message: missingCurlyMessage}
       ]
     },
     {
-      code: `<App prop={'foo'} attr={" foo "} />`,
-      output: '<App prop="foo" attr=" foo " />',
+      code: '<App>{\'foo "bar"\'}</App>',
+      output: '<App>foo \"bar\"</App>',
+      options: [{children: 'never'}],
+      errors: [{message: unnecessaryCurlyMessage}]
+    },
+    {
+      code: '<App>{\"foo \'bar\'\"}</App>',
+      output: '<App>foo \'bar\'</App>',
+      errors: [{message: unnecessaryCurlyMessage}],
+      options: [{children: 'never'}]
+    },
+    {
+      code: '<App prop={\"foo \'bar\' foo \"}>foo</App>',
+      output: '<App prop=\"foo \'bar\' foo \">foo</App>',
+      errors: [{message: unnecessaryCurlyMessage}],
+      options: [{props: 'never'}]
+    },
+    {
+      code: '<App prop={\'foo "bar"\'}>foo</App>',
+      output: '<App prop=\"foo \\\"bar\\\"\">foo</App>',
+      errors: [{message: unnecessaryCurlyMessage}],
+      options: [{props: 'never'}]
+    },
+    {
+      code: '<App prop={\'foo\'} attr={\" foo \"} />',
+      output: '<App prop=\"foo\" attr=\" foo \" />',
       errors: [
         {message: unnecessaryCurlyMessage}, {message: unnecessaryCurlyMessage}
       ],
       options: [{props: 'never'}]
     },
     {
-      code: `<App prop='foo' attr="bar" />`,
-      output: '<App prop={"foo"} attr={"bar"} />',
+      code: '<App prop=\'foo\' attr=\"bar\" />',
+      output: '<App prop={\"foo\"} attr={\"bar\"} />',
       errors: [
         {message: missingCurlyMessage}, {message: missingCurlyMessage}
       ],
       options: [{props: 'always'}]
     },
     {
-      code: `<App prop='foo' attr={"bar"} />`,
-      output: `<App prop={"foo"} attr={"bar"} />`,
+      code: '<App prop=\'foo\' attr={\"bar\"} />',
+      output: '<App prop={\"foo\"} attr={\"bar\"} />',
       errors: [{message: missingCurlyMessage}],
       options: [{props: 'always'}]
     },
     {
-      code: `<App prop={'foo'} attr='bar' />`,
-      output: `<App prop={'foo'} attr={"bar"} />`,
+      code: '<App prop={\'foo\'} attr=\'bar\' />',
+      output: '<App prop={\'foo\'} attr={\"bar\"} />',
       errors: [{message: missingCurlyMessage}],
       options: [{props: 'always'}]
-    },
-    {
-      code: `<App prop='foo &middot; bar' />`,
-      errors: [{message: missingCurlyMessage}],
-      options: [{props: 'always'}]
-    },
-    {
-      code: '<App>foo &middot; bar</App>',
-      errors: [{message: missingCurlyMessage}],
-      options: [{children: 'always'}]
-    },
-    {
-      code: `<App>{'foo "bar"'}</App>`,
-      output: `<App>foo "bar"</App>`,
-      errors: [{message: unnecessaryCurlyMessage}],
-      options: [{children: 'never'}]
-    },
-    {
-      code: `<App>{"foo 'bar'"}</App>`,
-      output: `<App>foo 'bar'</App>`,
-      errors: [{message: unnecessaryCurlyMessage}],
-      options: [{children: 'never'}]
-    },
-    {
-      code: [
-        '<App prop="    ',
-        '   a     ',
-        '     b      c',
-        '        d',
-        '">',
-        '  a',
-        '      b     c   ',
-        '         d      ',
-        '</App>'
-      ].join('\n'),
-      errors: [
-        {message: missingCurlyMessage}, {message: missingCurlyMessage}
-      ],
-      options: ['always']
-    },
-    {
-      code: [
-        `<App prop='    `,
-        '   a     ',
-        '     b      c',
-        '        d',
-        `'>`,
-        '  a',
-        '      b     c   ',
-        '         d      ',
-        '</App>'
-      ].join('\n'),
-      errors: [
-        {message: missingCurlyMessage}, {message: missingCurlyMessage}
-      ],
-      options: ['always']
     }
   ]
 });