From b9a8aff93d415d9df718e9aa194cb2d10b2fb520 Mon Sep 17 00:00:00 2001 From: David Petersen Date: Tue, 16 Aug 2016 10:02:58 -0500 Subject: [PATCH] Handle nested levels of spread properties (Fixes #771) --- lib/rules/no-danger-with-children.js | 22 +++++++++++++++++---- tests/lib/rules/no-danger-with-children.js | 23 ++++++++++++++++++++-- 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/lib/rules/no-danger-with-children.js b/lib/rules/no-danger-with-children.js index 8482b0fcb2..98bcb73cbc 100644 --- a/lib/rules/no-danger-with-children.js +++ b/lib/rules/no-danger-with-children.js @@ -19,14 +19,30 @@ module.exports = { schema: [] // no options }, create: function(context) { + function findSpreadVariable(name) { + return variableUtil.variablesInScope(context).find(function (item) { + return item.name === name; + }); + } /** * Takes a ObjectExpression and returns the value of the prop if it has it * @param {object} node - ObjectExpression node * @param {string} propName - name of the prop to look for */ function findObjectProp(node, propName) { + if (!node.properties) { + return false; + } return node.properties.find(function(prop) { - return prop.key.name === propName; + if (prop.type === 'Property') { + return prop.key.name === propName; + } else if (prop.type === 'ExperimentalSpreadProperty') { + var variable = findSpreadVariable(prop.argument.name); + if (variable && variable.defs[0].node.init) { + return findObjectProp(variable.defs[0].node.init, propName); + } + } + return false; }); } @@ -39,9 +55,7 @@ module.exports = { var attributes = node.openingElement.attributes; return attributes.find(function (attribute) { if (attribute.type === 'JSXSpreadAttribute') { - var variable = variableUtil.variablesInScope(context).find(function (item) { - return item.name === attribute.argument.name; - }); + var variable = findSpreadVariable(attribute.argument.name); if (variable && variable.defs[0].node.init) { return findObjectProp(variable.defs[0].node.init, propName); } diff --git a/tests/lib/rules/no-danger-with-children.js b/tests/lib/rules/no-danger-with-children.js index cc045ae5cd..4713d2e923 100644 --- a/tests/lib/rules/no-danger-with-children.js +++ b/tests/lib/rules/no-danger-with-children.js @@ -14,6 +14,7 @@ var RuleTester = require('eslint').RuleTester; var parserOptions = { ecmaVersion: 6, ecmaFeatures: { + experimentalObjectRestSpread: true, jsx: true } }; @@ -46,11 +47,20 @@ ruleTester.run('no-danger-with-children', rule, { }, { code: [ - 'const props = { children: "Children" };', + 'const moreProps = { className: "eslint" };', + 'const props = { children: "Children", ...moreProps };', '
' ].join('\n'), parserOptions: parserOptions }, + { + code: [ + 'const otherProps = { children: "Children" };', + 'const { a, b, ...props } = otherProps;', + '
', + ].join('\n'), + parserOptions: parserOptions + }, { code: 'Children', parserOptions: parserOptions @@ -103,7 +113,6 @@ ruleTester.run('no-danger-with-children', rule, { code: [ 'const props = { children: "Children", dangerouslySetInnerHTML: { __html: "HTML" } };', '
', - '//foobar' ].join('\n'), errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}], parserOptions: parserOptions @@ -185,6 +194,16 @@ ruleTester.run('no-danger-with-children', rule, { ].join('\n'), errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}], parserOptions: parserOptions + }, + { + code: [ + 'const moreProps = { children: "Children" };', + 'const otherProps = { ...moreProps };', + 'const props = { ...otherProps, dangerouslySetInnerHTML: { __html: "HTML" } };', + 'React.createElement("div", props);' + ].join('\n'), + errors: [{message: 'Only set one of `children` or `props.dangerouslySetInnerHTML`'}], + parserOptions: parserOptions } ] });