From ca87883a3b5d88e0a22755345513f12a22a97968 Mon Sep 17 00:00:00 2001 From: Glen Mailer Date: Sun, 1 Mar 2015 16:44:37 +0000 Subject: [PATCH] Add jsx-uses-react rule This rule somewhat unusual, in that it modifies the behaviour of a core eslint rule. The alternative would be to copy-paste the original rule and modify it. That would require users to disable the core rule and replace with this one --- docs/rules/jsx-uses-react.md | 29 ++++++++++++++++++++ index.js | 2 ++ lib/rules/jsx-uses-react.js | 44 +++++++++++++++++++++++++++++++ tests/lib/rules/jsx-uses-react.js | 31 ++++++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 docs/rules/jsx-uses-react.md create mode 100644 lib/rules/jsx-uses-react.js create mode 100644 tests/lib/rules/jsx-uses-react.js diff --git a/docs/rules/jsx-uses-react.md b/docs/rules/jsx-uses-react.md new file mode 100644 index 0000000000..1002eda8e3 --- /dev/null +++ b/docs/rules/jsx-uses-react.md @@ -0,0 +1,29 @@ +# Make JSX count towards use of a declared variable (jsx-uses-react) + +JSX expands to a call to `React.createElement`, a file which includes `React` +but only uses JSX should still consider the `React` variable used. + +This rule has no effect if the `no-unused-vars` rule is not enabled. + +## Rule Details + +The following patterns are considered warnings: + +```js +var React = require('react'); // and other equivalent imports + +// nothing to do with React +``` + +The following patterns are not considered warnings: + +```js +var React = require('react'); + +var elem =
Some Stuff
; +``` + +## When Not To Use It + +If you are not using JSX, or React is delcared as global variable, this rule +will not be useful. diff --git a/index.js b/index.js index 83b40b8a94..969126b1ce 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,7 @@ module.exports = { rules: { + 'jsx-uses-react': require('./lib/rules/jsx-uses-react'), 'no-multi-comp': require('./lib/rules/no-multi-comp'), 'prop-types': require('./lib/rules/prop-types'), 'display-name': require('./lib/rules/display-name'), @@ -11,6 +12,7 @@ module.exports = { 'no-did-update-set-state': require('./lib/rules/no-did-update-set-state') }, rulesConfig: { + 'jsx-uses-react': 0, 'no-multi-comp': 0, 'prop-types': 0, 'display-name': 0, diff --git a/lib/rules/jsx-uses-react.js b/lib/rules/jsx-uses-react.js new file mode 100644 index 0000000000..9202c724f5 --- /dev/null +++ b/lib/rules/jsx-uses-react.js @@ -0,0 +1,44 @@ +/** + * @fileoverview Count as use of the React variable + * @author Glen Mailer + */ +'use strict'; + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = function(context) { + + function flagReactAsUsedInJSX() { + var scope = context.getScope(), + variables = scope.variables, + i, + len; + + while (scope.type !== "global") { + scope = scope.upper; + variables = [].concat.apply(scope.variables, variables); + } + + // mark first React found with the same special flag used by no-unused-vars + for (i = 0, len = variables.length; i < len; i++) { + if (variables[i].name === 'React') { + variables[i].eslintJSXUsed = true; + return; + } + } + } + + // -------------------------------------------------------------------------- + // Public + // -------------------------------------------------------------------------- + + return { + + 'JSXOpeningElement': function() { + flagReactAsUsedInJSX(); + } + }; + +}; diff --git a/tests/lib/rules/jsx-uses-react.js b/tests/lib/rules/jsx-uses-react.js new file mode 100644 index 0000000000..cc424bcbc7 --- /dev/null +++ b/tests/lib/rules/jsx-uses-react.js @@ -0,0 +1,31 @@ +/** + * @fileoverview Tests for jsx-uses-react + * @author Glen Mailer + */ + +"use strict"; + +// ----------------------------------------------------------------------------- +// Requirements +// ----------------------------------------------------------------------------- + +var eslint = require('eslint').linter; +var ESLintTester = require('eslint-tester'); + +// ----------------------------------------------------------------------------- +// Tests +// ----------------------------------------------------------------------------- + +var eslintTester = new ESLintTester(eslint); +eslint.defineRule('jsx-uses-react', require('../../../lib/rules/jsx-uses-react')); +eslintTester.addRuleTest("node_modules/eslint/lib/rules/no-unused-vars", { + valid: [ + {code: "/*eslint jsx-uses-react:1*/ var App, React; ;", ecmaFeatures: {jsx: true}}, + {code: "/*eslint jsx-uses-react:1*/ var React;
;", ecmaFeatures: {jsx: true}}, + {code: "/*eslint jsx-uses-react:1*/ var React; (function () {
})();", ecmaFeatures: {jsx: true}} + ], + invalid: [ + {code: "/*eslint jsx-uses-react:1*/ var React;", + errors: [{message: "React is defined but never used"}], ecmaFeatures: {jsx: true}} + ] +});