Skip to content

Commit a8737b5

Browse files
committed
Merge pull request #72 from AlexKVal/38_sort_propTypes
Add jsx-sort-prop-types rule (fixes #38)
2 parents 76d5cd4 + 4c1a524 commit a8737b5

File tree

5 files changed

+509
-1
lines changed

5 files changed

+509
-1
lines changed

README.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ Finally, enable all of the rules that you would like to use.
4747
"react/jsx-quotes": 1,
4848
"react/jsx-no-undef": 1,
4949
"react/jsx-sort-props": 1,
50+
"react/jsx-sort-prop-types": 1,
5051
"react/jsx-uses-react": 1,
5152
"react/jsx-uses-vars": 1,
5253
"react/no-did-mount-set-state": 1,
@@ -68,6 +69,7 @@ Finally, enable all of the rules that you would like to use.
6869
* [jsx-quotes](docs/rules/jsx-quotes.md): Enforce quote style for JSX attributes
6970
* [jsx-no-undef](docs/rules/jsx-no-undef.md): Disallow undeclared variables in JSX
7071
* [jsx-sort-props](docs/rules/jsx-sort-props.md): Enforce props alphabetical sorting
72+
* [jsx-sort-prop-types](docs/rules/jsx-sort-prop-types.md): Enforce propTypes declarations alphabetical sorting
7173
* [jsx-uses-react](docs/rules/jsx-uses-react.md): Prevent React to be incorrectly marked as unused
7274
* [jsx-uses-vars](docs/rules/jsx-uses-vars.md): Prevent variables used in JSX to be incorrectly marked as unused
7375
* [no-did-mount-set-state](docs/rules/no-did-mount-set-state.md): Prevent usage of setState in componentDidMount
@@ -111,4 +113,3 @@ ESLint-plugin-React is licensed under the [MIT License](http://www.opensource.or
111113

112114
[status-url]: https://github.com/yannickcr/eslint-plugin-react/pulse
113115
[status-image]: http://img.shields.io/badge/status-maintained-brightgreen.svg?style=flat-square
114-

docs/rules/jsx-sort-prop-types.md

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Enforce propTypes declarations alphabetical sorting (jsx-sort-prop-types)
2+
3+
Some developers prefer to sort propsTypes declarations alphabetically to be able to find necessary declaration easier at the later time. Others feel that it adds complexity and becomes burden to maintain.
4+
5+
## Rule Details
6+
7+
This rule checks all JSX components and verifies that all propsTypes declarations are sorted alphabetically.
8+
The default configuration of the rule is case-sensitive.
9+
This rule is off by default.
10+
11+
The following patterns are considered warnings:
12+
13+
```js
14+
var Component = React.createClass({
15+
propTypes: {
16+
z: React.PropTypes.number,
17+
a: React.PropTypes.any,
18+
b: React.PropTypes.string
19+
},
20+
...
21+
});
22+
23+
class Component extends React.Component {
24+
...
25+
}
26+
Component.propTypes = {
27+
z: React.PropTypes.number,
28+
a: React.PropTypes.any,
29+
b: React.PropTypes.string
30+
};
31+
32+
class Component extends React.Component {
33+
static propTypes = {
34+
z: React.PropTypes.any,
35+
y: React.PropTypes.any,
36+
a: React.PropTypes.any
37+
}
38+
render() {
39+
return <div />;
40+
}
41+
}
42+
```
43+
44+
The following patterns are considered okay and do not cause warnings:
45+
46+
```js
47+
var Component = React.createClass({
48+
propTypes: {
49+
a: React.PropTypes.number,
50+
b: React.PropTypes.any,
51+
c: React.PropTypes.string
52+
},
53+
...
54+
});
55+
56+
class Component extends React.Component {
57+
...
58+
}
59+
Component.propTypes = {
60+
a: React.PropTypes.string,
61+
b: React.PropTypes.any,
62+
c: React.PropTypes.string
63+
};
64+
65+
class Component extends React.Component {
66+
static propTypes = {
67+
a: React.PropTypes.any,
68+
b: React.PropTypes.any,
69+
c: React.PropTypes.any
70+
}
71+
render() {
72+
return <div />;
73+
}
74+
}
75+
```
76+
77+
## Rule Options
78+
79+
```js
80+
...
81+
"jsx-sort-prop-types": [<enabled>, { "ignoreCase": <boolean> }]
82+
...
83+
```
84+
85+
### `ignoreCase`
86+
87+
When `true` the rule ignores the case-sensitivity of the declarations order.
88+
89+
## When not to use
90+
91+
This rule is a formatting preference and not following it won't negatively affect the quality of your code. If alphabetizing props declarations isn't a part of your coding standards, then you can leave this rule off.

index.js

+2
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ module.exports = {
1616
'jsx-quotes': require('./lib/rules/jsx-quotes'),
1717
'no-unknown-property': require('./lib/rules/no-unknown-property'),
1818
'jsx-sort-props': require('./lib/rules/jsx-sort-props'),
19+
'jsx-sort-prop-types': require('./lib/rules/jsx-sort-prop-types'),
1920
'jsx-boolean-value': require('./lib/rules/jsx-boolean-value')
2021
},
2122
rulesConfig: {
@@ -33,6 +34,7 @@ module.exports = {
3334
'jsx-quotes': 0,
3435
'no-unknown-property': 0,
3536
'jsx-sort-props': 0,
37+
'jsx-sort-prop-types': 0,
3638
'jsx-boolean-value': 0
3739
}
3840
};

lib/rules/jsx-sort-prop-types.js

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/**
2+
* @fileoverview Enforce propTypes declarations alphabetical sorting
3+
*/
4+
'use strict';
5+
6+
// ------------------------------------------------------------------------------
7+
// Rule Definition
8+
// ------------------------------------------------------------------------------
9+
10+
module.exports = function(context) {
11+
12+
var configuration = context.options[0] || {};
13+
var ignoreCase = configuration.ignoreCase || false;
14+
15+
/**
16+
* Checks if node is `propTypes` declaration
17+
* @param {ASTNode} node The AST node being checked.
18+
* @returns {Boolean} True if node is `propTypes` declaration, false if not.
19+
*/
20+
function isPropTypesDeclaration(node) {
21+
22+
// Special case for class properties
23+
// (babel-eslint does not expose property name so we have to rely on tokens)
24+
if (node.type === 'ClassProperty') {
25+
var tokens = context.getFirstTokens(node, 2);
26+
if (tokens[0].value === 'propTypes' || tokens[1].value === 'propTypes') {
27+
return true;
28+
}
29+
return false;
30+
}
31+
32+
return Boolean(
33+
node &&
34+
node.name === 'propTypes'
35+
);
36+
}
37+
38+
/**
39+
* Checks if propTypes declarations are sorted
40+
* @param {Array} declarations The array of AST nodes being checked.
41+
* @returns {void}
42+
*/
43+
function checkSorted(declarations) {
44+
declarations.reduce(function(prev, curr) {
45+
var prevPropName = prev.key.name;
46+
var currenPropName = curr.key.name;
47+
48+
if (ignoreCase) {
49+
prevPropName = prevPropName.toLowerCase();
50+
currenPropName = currenPropName.toLowerCase();
51+
}
52+
53+
if (currenPropName < prevPropName) {
54+
context.report(curr, 'Prop types declarations should be sorted alphabetically');
55+
return prev;
56+
}
57+
58+
return curr;
59+
}, declarations[0]);
60+
}
61+
62+
return {
63+
ClassProperty: function(node) {
64+
if (isPropTypesDeclaration(node) && node.value.type === 'ObjectExpression') {
65+
checkSorted(node.value.properties);
66+
}
67+
},
68+
69+
MemberExpression: function(node) {
70+
if (isPropTypesDeclaration(node.property)) {
71+
var right = node.parent.right;
72+
if (right && right.type === 'ObjectExpression') {
73+
checkSorted(right.properties);
74+
}
75+
}
76+
},
77+
78+
ObjectExpression: function(node) {
79+
node.properties.forEach(function(property) {
80+
if (!isPropTypesDeclaration(property.key)) {
81+
return;
82+
}
83+
if (property.value.type === 'ObjectExpression') {
84+
checkSorted(property.value.properties);
85+
}
86+
});
87+
}
88+
89+
};
90+
};

0 commit comments

Comments
 (0)