Skip to content

Commit 46b9c97

Browse files
committed
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
1 parent 9c43de0 commit 46b9c97

File tree

4 files changed

+104
-0
lines changed

4 files changed

+104
-0
lines changed

docs/rules/jsx-uses-react.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# Make JSX count towards use of a declared variable (jsx-uses-react)
2+
3+
JSX expands to a call to `React.createElement`, a file which includes `React`
4+
but only uses JSX should still consider the `React` variable used.
5+
6+
## Rule Details
7+
8+
The following patterns are considered warnings:
9+
10+
```js
11+
var React = require('react'); // and other equivalent imports
12+
13+
// nothing to do with React
14+
```
15+
16+
The following patterns are not considered warnings:
17+
18+
```js
19+
var React = require('react');
20+
21+
var elem = <div>Some Stuff</div>;
22+
```
23+
24+
## When Not To Use It
25+
26+
If you are not using JSX, or React is delcared as global variable, this rule
27+
will not be useful.

index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
module.exports = {
44
rules: {
5+
'jsx-uses-react': require('./lib/rules/jsx-uses-react'),
56
'no-multi-comp': require('./lib/rules/no-multi-comp'),
67
'prop-types': require('./lib/rules/prop-types'),
78
'display-name': require('./lib/rules/display-name'),
@@ -11,6 +12,7 @@ module.exports = {
1112
'no-did-update-set-state': require('./lib/rules/no-did-update-set-state')
1213
},
1314
rulesConfig: {
15+
'jsx-uses-react': 0,
1416
'no-multi-comp': 0,
1517
'prop-types': 0,
1618
'display-name': 0,

lib/rules/jsx-uses-react.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/**
2+
* @fileoverview Count <Jsx /> as use of the React variable
3+
* @author Glen Mailer
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Rule Definition
9+
// ------------------------------------------------------------------------------
10+
11+
module.exports = function(context) {
12+
13+
function flagReactAsUsedInJSX() {
14+
var scope = context.getScope(),
15+
variables = scope.variables,
16+
i,
17+
len;
18+
19+
while (scope.type !== "global") {
20+
scope = scope.upper;
21+
variables = [].concat.apply(scope.variables, variables);
22+
}
23+
24+
// mark first React found with the same special flag used by no-unused-vars
25+
for (i = 0, len = variables.length; i < len; i++) {
26+
if (variables[i].name === 'React') {
27+
variables[i].eslintJSXUsed = true;
28+
return;
29+
}
30+
}
31+
}
32+
33+
// --------------------------------------------------------------------------
34+
// Public
35+
// --------------------------------------------------------------------------
36+
37+
return {
38+
39+
'JSXOpeningElement': function() {
40+
flagReactAsUsedInJSX();
41+
}
42+
};
43+
44+
};

tests/lib/rules/jsx-uses-react.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/**
2+
* @fileoverview Tests for jsx-uses-react
3+
* @author Glen Mailer
4+
*/
5+
6+
"use strict";
7+
8+
// -----------------------------------------------------------------------------
9+
// Requirements
10+
// -----------------------------------------------------------------------------
11+
12+
var eslint = require('eslint').linter;
13+
var ESLintTester = require('eslint-tester');
14+
15+
// -----------------------------------------------------------------------------
16+
// Tests
17+
// -----------------------------------------------------------------------------
18+
19+
var eslintTester = new ESLintTester(eslint);
20+
eslint.defineRule('jsx-uses-react', require('../../../lib/rules/jsx-uses-react'));
21+
eslintTester.addRuleTest("node_modules/eslint/lib/rules/no-unused-vars", {
22+
valid: [
23+
{code: "/*eslint jsx-uses-react:1*/ var App, React; <App />;", ecmaFeatures: {jsx: true}},
24+
{code: "/*eslint jsx-uses-react:1*/ var React; <div />;", ecmaFeatures: {jsx: true}},
25+
{code: "/*eslint jsx-uses-react:1*/ var React; (function () { <div /> })();", ecmaFeatures: {jsx: true}}
26+
],
27+
invalid: [
28+
{code: "/*eslint jsx-uses-react:1*/ var React;",
29+
errors: [{message: "React is defined but never used"}], ecmaFeatures: {jsx: true}}
30+
]
31+
});

0 commit comments

Comments
 (0)