Skip to content

Commit 1062025

Browse files
committed
Add @jsx pragma support (fixes #23)
1 parent 00d5b85 commit 1062025

File tree

6 files changed

+79
-10
lines changed

6 files changed

+79
-10
lines changed

docs/rules/jsx-uses-react.md

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,40 @@
33
JSX expands to a call to `React.createElement`, a file which includes `React`
44
but only uses JSX should consider the `React` variable as used.
55

6+
If you are using the @jsx pragma this rule will mark the designated variable and not the `React` one.
7+
68
This rule has no effect if the `no-unused-vars` rule is not enabled.
79

810
## Rule Details
911

1012
The following patterns are considered warnings:
1113

1214
```js
13-
var React = require('react'); // and other equivalent imports
15+
var React = require('react');
1416

1517
// nothing to do with React
1618
```
1719

20+
```js
21+
/** @jsx Foo */
22+
var React = require('react');
23+
24+
var Hello = <div>Hello {this.props.name}</div>;
25+
```
26+
1827
The following patterns are not considered warnings:
1928

2029
```js
2130
var React = require('react');
2231

23-
var elem = <div>Some Stuff</div>;
32+
var Hello = <div>Hello {this.props.name}</div>;
33+
```
34+
35+
```js
36+
/** @jsx Foo */
37+
var Foo = require('foo');
38+
39+
var Hello = <div>Hello {this.props.name}</div>;
2440
```
2541

2642
## When Not To Use It

docs/rules/react-in-jsx-scope.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
When using JSX, `<a />` expands to `React.createElement("a")`. Therefore the
44
`React` variable must be in scope.
55

6+
If you are using the @jsx pragma this rule will check the designated variable and not the `React` one.
7+
68
## Rule Details
79

810
The following patterns are considered warnings:
@@ -11,10 +13,25 @@ The following patterns are considered warnings:
1113
var Hello = <div>Hello {this.props.name}</div>;
1214
```
1315

16+
```js
17+
/** @jsx Foo.bar */
18+
var React = require('react');
19+
20+
var Hello = <div>Hello {this.props.name}</div>;
21+
```
22+
1423
The following patterns are not considered warnings:
1524

1625
```js
17-
var React = require('react'); // or equivalent import
26+
var React = require('react');
27+
28+
var Hello = <div>Hello {this.props.name}</div>;
29+
```
30+
31+
```js
32+
/** @jsx Foo.bar */
33+
var Foo = require('foo');
34+
1835
var Hello = <div>Hello {this.props.name}</div>;
1936
```
2037

lib/rules/jsx-uses-react.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,30 @@
88
// Rule Definition
99
// ------------------------------------------------------------------------------
1010

11+
var JSX_ANNOTATION_REGEX = /^\*\s*@jsx\s+([^\s]+)/;
12+
1113
module.exports = function(context) {
1214

15+
var id = 'React';
16+
1317
// --------------------------------------------------------------------------
1418
// Public
1519
// --------------------------------------------------------------------------
1620

1721
return {
1822

1923
JSXOpeningElement: function() {
20-
context.markVariableAsUsed('React');
24+
context.markVariableAsUsed(id);
25+
},
26+
27+
BlockComment: function(node) {
28+
var matches = JSX_ANNOTATION_REGEX.exec(node.value);
29+
if (!matches) {
30+
return;
31+
}
32+
id = matches[1].split('.')[0];
2133
}
34+
2235
};
2336

2437
};

lib/rules/react-in-jsx-scope.js

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,12 @@
88
// Rule Definition
99
// -----------------------------------------------------------------------------
1010

11+
var JSX_ANNOTATION_REGEX = /^\*\s*@jsx\s+([^\s]+)/;
12+
1113
module.exports = function(context) {
1214

13-
var NOT_DEFINED_MESSAGE = '\'React\' must be in scope when using JSX';
15+
var id = 'React';
16+
var NOT_DEFINED_MESSAGE = '\'{{name}}\' must be in scope when using JSX';
1417

1518
function findVariable(variables, name) {
1619
var i, len;
@@ -41,9 +44,20 @@ module.exports = function(context) {
4144

4245
JSXOpeningElement: function(node) {
4346
var variables = variablesInScope();
44-
if (!findVariable(variables, 'React')) {
45-
context.report(node, NOT_DEFINED_MESSAGE);
47+
if (findVariable(variables, id)) {
48+
return;
49+
}
50+
context.report(node, NOT_DEFINED_MESSAGE, {
51+
name: id
52+
});
53+
},
54+
55+
BlockComment: function(node) {
56+
var matches = JSX_ANNOTATION_REGEX.exec(node.value);
57+
if (!matches) {
58+
return;
4659
}
60+
id = matches[1].split('.')[0];
4761
}
4862

4963
};

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@ eslint.defineRule('jsx-uses-react', require('../../../lib/rules/jsx-uses-react')
2121
eslintTester.addRuleTest('node_modules/eslint/lib/rules/no-unused-vars', {
2222
valid: [
2323
{code: '/*eslint jsx-uses-react:1*/ var React; <div />;', ecmaFeatures: {jsx: true}},
24-
{code: '/*eslint jsx-uses-react:1*/ var React; (function () { <div /> })();', ecmaFeatures: {jsx: true}}
24+
{code: '/*eslint jsx-uses-react:1*/ var React; (function () { <div /> })();', ecmaFeatures: {jsx: true}},
25+
{code: '/*eslint jsx-uses-react:1*/ /** @jsx Foo */ var Foo; <div />;', ecmaFeatures: {jsx: true}}
2526
],
2627
invalid: [
2728
{code: '/*eslint jsx-uses-react:1*/ var React;',
29+
errors: [{message: 'React is defined but never used'}], ecmaFeatures: {jsx: true}},
30+
{code: '/*eslint jsx-uses-react:1*/ /** @jsx Foo */ var React; <div />;',
2831
errors: [{message: 'React is defined but never used'}], ecmaFeatures: {jsx: true}}
2932
]
3033
});

tests/lib/rules/react-in-jsx-scope.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,20 @@ eslintTester.addRuleTest('lib/rules/react-in-jsx-scope', {
2424
{code: 'var React; <x-gif />;', args: [1, {vars: 'all'}], ecmaFeatures: {jsx: true}},
2525
{code: 'var React, App, a=1; <App attr={a} />;', ecmaFeatures: {jsx: true}},
2626
{code: 'var React, App, a=1; function elem() { return <App attr={a} />; }', ecmaFeatures: {jsx: true}},
27-
{code: 'var React, App; <App />;', args: [1, {vars: 'all'}], ecmaFeatures: {globalReturn: true, jsx: true}}
27+
{code: 'var React, App; <App />;', args: [1, {vars: 'all'}], ecmaFeatures: {globalReturn: true, jsx: true}},
28+
{code: '/** @jsx Foo */ var Foo, App; <App />;', args: [1, {vars: 'all'}], ecmaFeatures: {jsx: true}},
29+
{code: '/** @jsx Foo.Bar */ var Foo, App; <App />;', args: [1, {vars: 'all'}], ecmaFeatures: {jsx: true}}
2830
],
2931
invalid: [
3032
{code: 'var App, a = <App />;',
3133
errors: [{message: '\'React\' must be in scope when using JSX'}], ecmaFeatures: {jsx: true}},
3234
{code: 'var a = <App />;',
3335
errors: [{message: '\'React\' must be in scope when using JSX'}], ecmaFeatures: {jsx: true}},
3436
{code: 'var a = <img />;',
35-
errors: [{message: '\'React\' must be in scope when using JSX'}], ecmaFeatures: {jsx: true}}
37+
errors: [{message: '\'React\' must be in scope when using JSX'}], ecmaFeatures: {jsx: true}},
38+
{code: '/** @jsx React.DOM */ var a = <img />;',
39+
errors: [{message: '\'React\' must be in scope when using JSX'}], ecmaFeatures: {jsx: true}},
40+
{code: '/** @jsx Foo.bar */ var React, a = <img />;',
41+
errors: [{message: '\'Foo\' must be in scope when using JSX'}], ecmaFeatures: {jsx: true}}
3642
]
3743
});

0 commit comments

Comments
 (0)