Skip to content

Commit 57c6ccf

Browse files
lencioniyannickcr
authored andcommitted
Rename some JSX-specific rules to include jsx- prefix (fixes #668)
1 parent 30672e6 commit 57c6ccf

14 files changed

+292
-164
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
8181

8282
* [react/display-name](docs/rules/display-name.md): Prevent missing `displayName` in a React component definition
8383
* [react/forbid-prop-types](docs/rules/forbid-prop-types.md): Forbid certain propTypes
84-
* [react/no-comment-textnodes](docs/rules/no-comment-textnodes.md): Prevent comments from being inserted as text nodes
8584
* [react/no-danger](docs/rules/no-danger.md): Prevent usage of dangerous JSX properties
8685
* [react/no-deprecated](docs/rules/no-deprecated.md): Prevent usage of deprecated methods
8786
* [react/no-did-mount-set-state](docs/rules/no-did-mount-set-state.md): Prevent usage of `setState` in `componentDidMount`
@@ -98,13 +97,11 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
9897
* [react/prefer-stateless-function](docs/rules/prefer-stateless-function.md): Enforce stateless React Components to be written as a pure function
9998
* [react/prop-types](docs/rules/prop-types.md): Prevent missing props validation in a React component definition
10099
* [react/react-in-jsx-scope](docs/rules/react-in-jsx-scope.md): Prevent missing `React` when using JSX
101-
* [react/require-extension](docs/rules/require-extension.md): Restrict file extensions that may be required
102100
* [react/require-optimization](docs/rules/require-optimization.md): Enforce React components to have a shouldComponentUpdate method
103101
* [react/require-render-return](docs/rules/require-render-return.md): Enforce ES5 or ES6 class for returning value in render function
104102
* [react/self-closing-comp](docs/rules/self-closing-comp.md): Prevent extra closing tags for components without children
105103
* [react/sort-comp](docs/rules/sort-comp.md): Enforce component methods order
106104
* [react/sort-prop-types](docs/rules/sort-prop-types.md): Enforce propTypes declarations alphabetical sorting
107-
* [react/wrap-multilines](docs/rules/wrap-multilines.md): Prevent missing parentheses around multilines JSX (fixable)
108105

109106
## JSX-specific rules
110107

@@ -120,15 +117,18 @@ Finally, enable all of the rules that you would like to use. Use [our preset](#
120117
* [react/jsx-key](docs/rules/jsx-key.md): Validate JSX has key prop when in array or iterator
121118
* [react/jsx-max-props-per-line](docs/rules/jsx-max-props-per-line.md): Limit maximum of props on a single line in JSX
122119
* [react/jsx-no-bind](docs/rules/jsx-no-bind.md): Prevent usage of `.bind()` and arrow functions in JSX props
120+
* [react/jsx-no-comment-textnodes](docs/rules/jsx-no-comment-textnodes.md): Prevent comments from being inserted as text nodes
123121
* [react/jsx-no-duplicate-props](docs/rules/jsx-no-duplicate-props.md): Prevent duplicate props in JSX
124122
* [react/jsx-no-literals](docs/rules/jsx-no-literals.md): Prevent usage of unwrapped JSX strings
125123
* [react/jsx-no-target-blank](docs/rules/jsx-no-target-blank.md): Prevent usage of unsafe `target='_blank'`
126124
* [react/jsx-no-undef](docs/rules/jsx-no-undef.md): Disallow undeclared variables in JSX
127125
* [react/jsx-pascal-case](docs/rules/jsx-pascal-case.md): Enforce PascalCase for user-defined JSX components
126+
* [react/jsx-require-extension](docs/rules/jsx-require-extension.md): Restrict file extensions that may be required
128127
* [react/jsx-sort-props](docs/rules/jsx-sort-props.md): Enforce props alphabetical sorting
129128
* [react/jsx-space-before-closing](docs/rules/jsx-space-before-closing.md): Validate spacing before closing bracket in JSX (fixable)
130129
* [react/jsx-uses-react](docs/rules/jsx-uses-react.md): Prevent React to be incorrectly marked as unused
131130
* [react/jsx-uses-vars](docs/rules/jsx-uses-vars.md): Prevent variables used in JSX to be incorrectly marked as unused
131+
* [react/jsx-wrap-multilines](docs/rules/jsx-wrap-multilines.md): Prevent missing parentheses around multilines JSX (fixable)
132132

133133
## React Native rules
134134

docs/rules/no-comment-textnodes.md renamed to docs/rules/jsx-no-comment-textnodes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Prevent comments from being inserted as text nodes (no-comment-textnodes)
1+
# Prevent comments from being inserted as text nodes (jsx-no-comment-textnodes)
22

33
This rule prevents comment strings (e.g. beginning with `//` or `/*`) from being accidentally
44
injected as a text node in JSX statements.

docs/rules/require-extension.md renamed to docs/rules/jsx-require-extension.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Restrict file extensions that may be required (require-extension)
1+
# Restrict file extensions that may be required (jsx-require-extension)
22

33
`require()` statements should generally not include a file extension as there is a well defined mechanism for resolving a module ID to a specific file. This rule inspects the module ID being required and creates a warning if the ID contains a '.jsx' file extension.
44

@@ -29,7 +29,7 @@ The set of forbidden extensions is configurable. By default '.jsx' is blocked. I
2929

3030
```js
3131
"rules": {
32-
"react/require-extension": [1, { "extensions": [".js", ".jsx"] }],
32+
"react/jsx-require-extension": [1, { "extensions": [".js", ".jsx"] }],
3333
}
3434
```
3535

docs/rules/wrap-multilines.md renamed to docs/rules/jsx-wrap-multilines.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Prevent missing parentheses around multiline JSX (wrap-multilines)
1+
# Prevent missing parentheses around multiline JSX (jsx-wrap-multilines)
22

33
Wrapping multiline JSX in parentheses can improve readability and/or convenience. It optionally takes a second parameter in the form of an object, containing places to apply the rule. By default, `"declaration"`, `"assignment"`, and `"return"` syntax is checked, but these can be explicitly disabled. Any syntax type missing in the object will follow the default behavior (become enabled).
44

index.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ var rules = {
66
'prop-types': require('./lib/rules/prop-types'),
77
'display-name': require('./lib/rules/display-name'),
88
'wrap-multilines': require('./lib/rules/wrap-multilines'),
9+
'jsx-wrap-multilines': require('./lib/rules/jsx-wrap-multilines'),
910
'self-closing-comp': require('./lib/rules/self-closing-comp'),
1011
'no-comment-textnodes': require('./lib/rules/no-comment-textnodes'),
12+
'jsx-no-comment-textnodes': require('./lib/rules/jsx-no-comment-textnodes'),
1113
'no-danger': require('./lib/rules/no-danger'),
1214
'no-set-state': require('./lib/rules/no-set-state'),
1315
'no-is-mounted': require('./lib/rules/no-is-mounted'),
@@ -29,6 +31,7 @@ var rules = {
2931
'jsx-boolean-value': require('./lib/rules/jsx-boolean-value'),
3032
'sort-comp': require('./lib/rules/sort-comp'),
3133
'require-extension': require('./lib/rules/require-extension'),
34+
'jsx-require-extension': require('./lib/rules/jsx-require-extension'),
3235
'jsx-no-duplicate-props': require('./lib/rules/jsx-no-duplicate-props'),
3336
'jsx-max-props-per-line': require('./lib/rules/jsx-max-props-per-line'),
3437
'jsx-no-literals': require('./lib/rules/jsx-no-literals'),

lib/rules/jsx-no-comment-textnodes.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/**
2+
* @fileoverview Comments inside children section of tag should be placed inside braces.
3+
* @author Ben Vinegar
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Rule Definition
9+
// ------------------------------------------------------------------------------
10+
11+
module.exports = function(context) {
12+
function reportLiteralNode(node) {
13+
context.report(node, 'Comments inside children section of tag should be placed inside braces');
14+
}
15+
16+
// --------------------------------------------------------------------------
17+
// Public
18+
// --------------------------------------------------------------------------
19+
20+
return {
21+
Literal: function(node) {
22+
if (/^\s*\/(\/|\*)/m.test(node.value)) {
23+
// inside component, e.g. <div>literal</div>
24+
if (node.parent.type !== 'JSXAttribute' &&
25+
node.parent.type !== 'JSXExpressionContainer' &&
26+
node.parent.type.indexOf('JSX') !== -1) {
27+
reportLiteralNode(node);
28+
}
29+
}
30+
}
31+
};
32+
};
33+
34+
module.exports.schema = [{
35+
type: 'object',
36+
properties: {},
37+
additionalProperties: false
38+
}];

lib/rules/jsx-require-extension.js

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/**
2+
* @fileoverview Restrict file extensions that may be required
3+
* @author Scott Andrews
4+
*/
5+
'use strict';
6+
7+
var path = require('path');
8+
9+
// ------------------------------------------------------------------------------
10+
// Constants
11+
// ------------------------------------------------------------------------------
12+
13+
var DEFAULTS = {
14+
extensions: ['.jsx']
15+
};
16+
17+
var PKG_REGEX = /^[^\.]((?!\/).)*$/;
18+
19+
// ------------------------------------------------------------------------------
20+
// Rule Definition
21+
// ------------------------------------------------------------------------------
22+
23+
module.exports = function(context) {
24+
25+
function isPackage(id) {
26+
return PKG_REGEX.test(id);
27+
}
28+
29+
function isRequire(expression) {
30+
return expression.callee.name === 'require';
31+
}
32+
33+
function getId(expression) {
34+
return expression.arguments[0] && expression.arguments[0].value;
35+
}
36+
37+
function getExtension(id) {
38+
return path.extname(id || '');
39+
}
40+
41+
function getExtensionsConfig() {
42+
return context.options[0] && context.options[0].extensions || DEFAULTS.extensions;
43+
}
44+
45+
var forbiddenExtensions = getExtensionsConfig().reduce(function (extensions, extension) {
46+
extensions[extension] = true;
47+
return extensions;
48+
}, Object.create(null));
49+
50+
function isForbiddenExtension(ext) {
51+
return ext in forbiddenExtensions;
52+
}
53+
54+
// --------------------------------------------------------------------------
55+
// Public
56+
// --------------------------------------------------------------------------
57+
58+
return {
59+
60+
CallExpression: function(node) {
61+
if (isRequire(node)) {
62+
var id = getId(node);
63+
var ext = getExtension(id);
64+
if (!isPackage(id) && isForbiddenExtension(ext)) {
65+
context.report({
66+
node: node,
67+
message: 'Unable to require module with extension \'' + ext + '\''
68+
});
69+
}
70+
}
71+
}
72+
73+
};
74+
75+
};
76+
77+
module.exports.schema = [{
78+
type: 'object',
79+
properties: {
80+
extensions: {
81+
type: 'array',
82+
items: {
83+
type: 'string'
84+
}
85+
}
86+
},
87+
additionalProperties: false
88+
}];

lib/rules/jsx-wrap-multilines.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* @fileoverview Prevent missing parentheses around multilines JSX
3+
* @author Yannick Croissant
4+
*/
5+
'use strict';
6+
7+
// ------------------------------------------------------------------------------
8+
// Constants
9+
// ------------------------------------------------------------------------------
10+
11+
var DEFAULTS = {
12+
declaration: true,
13+
assignment: true,
14+
return: true
15+
};
16+
17+
// ------------------------------------------------------------------------------
18+
// Rule Definition
19+
// ------------------------------------------------------------------------------
20+
21+
module.exports = function(context) {
22+
23+
var sourceCode = context.getSourceCode();
24+
25+
function isParenthesised(node) {
26+
var previousToken = sourceCode.getTokenBefore(node);
27+
var nextToken = sourceCode.getTokenAfter(node);
28+
29+
return previousToken && nextToken &&
30+
previousToken.value === '(' && previousToken.range[1] <= node.range[0] &&
31+
nextToken.value === ')' && nextToken.range[0] >= node.range[1];
32+
}
33+
34+
function isMultilines(node) {
35+
return node.loc.start.line !== node.loc.end.line;
36+
}
37+
38+
function check(node) {
39+
if (!node || node.type !== 'JSXElement') {
40+
return;
41+
}
42+
43+
if (!isParenthesised(node) && isMultilines(node)) {
44+
context.report({
45+
node: node,
46+
message: 'Missing parentheses around multilines JSX',
47+
fix: function(fixer) {
48+
return fixer.replaceText(node, '(' + sourceCode.getText(node) + ')');
49+
}
50+
});
51+
}
52+
}
53+
54+
function isEnabled(type) {
55+
var userOptions = context.options[0] || {};
56+
if (({}).hasOwnProperty.call(userOptions, type)) {
57+
return userOptions[type];
58+
}
59+
return DEFAULTS[type];
60+
}
61+
62+
// --------------------------------------------------------------------------
63+
// Public
64+
// --------------------------------------------------------------------------
65+
66+
return {
67+
68+
VariableDeclarator: function(node) {
69+
if (isEnabled('declaration')) {
70+
check(node.init);
71+
}
72+
},
73+
74+
AssignmentExpression: function(node) {
75+
if (isEnabled('assignment')) {
76+
check(node.right);
77+
}
78+
},
79+
80+
ReturnStatement: function(node) {
81+
if (isEnabled('return')) {
82+
check(node.argument);
83+
}
84+
}
85+
};
86+
87+
};
88+
89+
module.exports.schema = [{
90+
type: 'object',
91+
properties: {
92+
declaration: {
93+
type: 'boolean'
94+
},
95+
assignment: {
96+
type: 'boolean'
97+
},
98+
return: {
99+
type: 'boolean'
100+
}
101+
},
102+
additionalProperties: false
103+
}];

lib/rules/no-comment-textnodes.js

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,32 @@
11
/**
22
* @fileoverview Comments inside children section of tag should be placed inside braces.
33
* @author Ben Vinegar
4+
* @deprecated
45
*/
56
'use strict';
67

78
// ------------------------------------------------------------------------------
89
// Rule Definition
910
// ------------------------------------------------------------------------------
1011

11-
module.exports = function(context) {
12-
function reportLiteralNode(node) {
13-
context.report(node, 'Comments inside children section of tag should be placed inside braces');
14-
}
15-
16-
// --------------------------------------------------------------------------
17-
// Public
18-
// --------------------------------------------------------------------------
12+
var util = require('util');
13+
var jsxNoCommentTextnodes = require('./jsx-no-comment-textnodes');
14+
var isWarnedForDeprecation = false;
1915

20-
return {
21-
Literal: function(node) {
22-
if (/^\s*\/(\/|\*)/m.test(node.value)) {
23-
// inside component, e.g. <div>literal</div>
24-
if (node.parent.type !== 'JSXAttribute' &&
25-
node.parent.type !== 'JSXExpressionContainer' &&
26-
node.parent.type.indexOf('JSX') !== -1) {
27-
reportLiteralNode(node);
28-
}
16+
module.exports = function(context) {
17+
return util._extend(jsxNoCommentTextnodes(context), {
18+
Program: function() {
19+
if (isWarnedForDeprecation || /\=-(f|-format)=/.test(process.argv.join('='))) {
20+
return;
2921
}
22+
23+
/* eslint-disable no-console */
24+
console.log('The react/no-comment-textnodes rule is deprecated. Please ' +
25+
'use the react/jsx-no-comment-textnodes rule instead.');
26+
/* eslint-enable no-console */
27+
isWarnedForDeprecation = true;
3028
}
31-
};
29+
});
3230
};
3331

3432
module.exports.schema = [{

0 commit comments

Comments
 (0)