From a02db45feb4df84efee99b8fada2f179c9e25860 Mon Sep 17 00:00:00 2001 From: Joshua Stiefer Date: Wed, 4 Jan 2017 21:25:05 -0700 Subject: [PATCH] Add `importedOnly` option for jsx-no-undef rule With the `importedOnly` option enabled, the global scope will be ignored when checking for defined components. Without this option enabled, Pascal case global variables will be allowed when checking for defined components. --- docs/rules/jsx-no-undef.md | 46 +++++++++++++++++++++++++++++++ lib/rules/jsx-no-undef.js | 22 +++++++++++++-- tests/lib/rules/jsx-no-undef.js | 49 +++++++++++++++++++++++++++++++++ 3 files changed, 115 insertions(+), 2 deletions(-) diff --git a/docs/rules/jsx-no-undef.md b/docs/rules/jsx-no-undef.md index 00cae519d5..f6a99ab16f 100644 --- a/docs/rules/jsx-no-undef.md +++ b/docs/rules/jsx-no-undef.md @@ -18,6 +18,52 @@ var Hello = require('./Hello'); ; ``` +## Rule Options + +```js +... +"react/jsx-no-undef": [, { "disallowGlobals": }] +... +``` + +### `importedOnly` + +When `true` the rule will ignore the global scope when checking for defined Components. + +The following patterns are considered okay and do not cause warnings: + +```jsx +var MyComponent = require('./MyComponent'); +var Hello = React.createClass({ + render: function() { + return ; + } +}); +module.exports = Hello; +``` + +```jsx +var Text = require('./Text'); +var Hello = React.createClass({ + render: function() { + return Hello; + } +}); +module.exports = Hello; +``` + +The following patterns will cause warnings: + +```jsx +// will ignore Text in the global scope and warn +var Hello = React.createClass({ + render: function() { + return Hello; + } +}); +module.exports = Hello; +``` + ## When Not To Use It If you are not using JSX then you can disable this rule. diff --git a/lib/rules/jsx-no-undef.js b/lib/rules/jsx-no-undef.js index 7639af1671..6f02f27d2a 100644 --- a/lib/rules/jsx-no-undef.js +++ b/lib/rules/jsx-no-undef.js @@ -26,11 +26,22 @@ module.exports = { category: 'Possible Errors', recommended: true }, - schema: [] + schema: [{ + type: 'object', + properties: { + disallowGlobals: { + type: 'boolean' + } + }, + additionalProperties: false + }] }, create: function(context) { + var config = context.options[0] || {}; + var disallowGlobals = config.disallowGlobals || false; + /** * Compare an identifier with the variables declared in the scope * @param {ASTNode} node - Identifier or JSXIdentifier node @@ -38,7 +49,10 @@ module.exports = { */ function checkIdentifierInJSX(node) { var scope = context.getScope(); + var sourceCode = context.getSourceCode(); + var sourceType = sourceCode.ast.sourceType; var variables = scope.variables; + var scopeType = 'global'; var i; var len; @@ -47,7 +61,11 @@ module.exports = { return; } - while (scope.type !== 'global') { + if (disallowGlobals && sourceType === 'module') { + scopeType = 'module'; + } + + while (scope.type !== scopeType) { scope = scope.upper; variables = scope.variables.concat(variables); } diff --git a/tests/lib/rules/jsx-no-undef.js b/tests/lib/rules/jsx-no-undef.js index 1fa3732acd..2194e024d7 100644 --- a/tests/lib/rules/jsx-no-undef.js +++ b/tests/lib/rules/jsx-no-undef.js @@ -56,6 +56,26 @@ ruleTester.run('jsx-no-undef', rule, { '}' ].join('\n'), parserOptions: parserOptions + }, { + code: 'var React; React.render();', + parserOptions: parserOptions, + globals: { + Text: true + } + }, { + code: [ + 'import Text from "cool-module";', + 'const TextWrapper = function (props) {', + ' return (', + ' ', + ' );', + '};' + ].join('\n'), + options: [{ + disallowGlobals: true + }], + parser: 'babel-eslint', + parserOptions: parserOptions }], invalid: [{ code: '/*eslint no-undef:1*/ var React; React.render();', @@ -87,5 +107,34 @@ ruleTester.run('jsx-no-undef', rule, { message: '\'appp\' is not defined.' }], parserOptions: parserOptions + }, { + code: [ + 'const TextWrapper = function (props) {', + ' return (', + ' ', + ' );', + '};', + 'export default TextWrapper;' + ].join('\n'), + errors: [{ + message: '\'Text\' is not defined.' + }], + options: [{ + disallowGlobals: true + }], + parser: 'babel-eslint', + parserOptions: parserOptions, + globals: { + Text: true + } + }, { + code: '/*eslint no-undef:1*/ var React; React.render();', + errors: [{ + message: '\'Foo\' is not defined.' + }], + options: [{ + disallowGlobals: true + }], + parserOptions: parserOptions }] });