Skip to content

Commit 003eed4

Browse files
committed
Merge pull request #429 from lencioni/sort-comp-static-methods
Add static method support to sort-comp (fixes #128)
2 parents e716f99 + b862347 commit 003eed4

File tree

2 files changed

+53
-27
lines changed

2 files changed

+53
-27
lines changed

docs/rules/sort-comp.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@ When creating React components it is more convenient to always follow the same o
88

99
With default configuration the following organisation must be followed:
1010

11-
1. lifecycle methods: `displayName`, `propTypes`, `contextTypes`, `childContextTypes`, `mixins`, `statics`,`defaultProps`, `constructor`, `getDefaultProps`, `getInitialState`, `state`, `getChildContext`, `componentWillMount`, `componentDidMount`, `componentWillReceiveProps`, `shouldComponentUpdate`, `componentWillUpdate`, `componentDidUpdate`, `componentWillUnmount` (in this order).
12-
2. custom methods
13-
3. `render` method
11+
1. static methods
12+
2. lifecycle methods: `displayName`, `propTypes`, `contextTypes`, `childContextTypes`, `mixins`, `statics`,`defaultProps`, `constructor`, `getDefaultProps`, `getInitialState`, `state`, `getChildContext`, `componentWillMount`, `componentDidMount`, `componentWillReceiveProps`, `shouldComponentUpdate`, `componentWillUpdate`, `componentDidUpdate`, `componentWillUnmount` (in this order).
13+
3. custom methods
14+
4. `render` method
1415

1516
The following patterns are considered warnings:
1617

@@ -53,6 +54,7 @@ The default configuration is:
5354
```js
5455
{
5556
order: [
57+
'static-methods',
5658
'lifecycle',
5759
'everything-else',
5860
'render'
@@ -83,9 +85,10 @@ The default configuration is:
8385
}
8486
```
8587

86-
* `lifecycle` is refering to the `lifecycle` group defined in `groups`.
88+
* `static-methods` is a special keyword that refers to static class methods.
89+
* `lifecycle` is referring to the `lifecycle` group defined in `groups`.
8790
* `everything-else` is a special group that match all the methods that do not match any of the other groups.
88-
* `render` is refering to the `render` method.
91+
* `render` is referring to the `render` method.
8992

9093
You can override this configuration to match your needs.
9194

@@ -94,6 +97,7 @@ For example, if you want to place your event handlers (`onClick`, `onSubmit`, et
9497
```js
9598
"react/sort-comp": [1, {
9699
order: [
100+
'static-methods',
97101
'lifecycle',
98102
'/^on.+$/',
99103
'render',
@@ -129,6 +133,7 @@ If you want to split your `render` method into smaller ones and keep them just b
129133
```js
130134
"react/sort-comp": [1, {
131135
order: [
136+
'static-methods',
132137
'lifecycle',
133138
'everything-else',
134139
'rendering',

lib/rules/sort-comp.js

+43-22
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ module.exports = Components.detect(function(context, components) {
4646

4747
var methodsOrder = getMethodsOrder({
4848
order: [
49+
'static-methods',
4950
'lifecycle',
5051
'everything-else',
5152
'render'
@@ -83,7 +84,7 @@ module.exports = Components.detect(function(context, components) {
8384

8485
/**
8586
* Get indexes of the matching patterns in methods order configuration
86-
* @param {String} method - Method name.
87+
* @param {Object} method - Method metadata.
8788
* @returns {Array} The matching patterns indexes. Return [Infinity] if there is no match.
8889
*/
8990
function getRefPropIndexes(method) {
@@ -92,15 +93,29 @@ module.exports = Components.detect(function(context, components) {
9293
var i;
9394
var j;
9495
var indexes = [];
95-
for (i = 0, j = methodsOrder.length; i < j; i++) {
96-
isRegExp = methodsOrder[i].match(regExpRegExp);
97-
if (isRegExp) {
98-
matching = new RegExp(isRegExp[1], isRegExp[2]).test(method);
99-
} else {
100-
matching = methodsOrder[i] === method;
96+
97+
if (method.static) {
98+
for (i = 0, j = methodsOrder.length; i < j; i++) {
99+
if (methodsOrder[i] === 'static-methods') {
100+
indexes.push(i);
101+
break;
102+
}
101103
}
102-
if (matching) {
103-
indexes.push(i);
104+
}
105+
106+
// Either this is not a static method or static methods are not specified
107+
// in the methodsOrder.
108+
if (indexes.length === 0) {
109+
for (i = 0, j = methodsOrder.length; i < j; i++) {
110+
isRegExp = methodsOrder[i].match(regExpRegExp);
111+
if (isRegExp) {
112+
matching = new RegExp(isRegExp[1], isRegExp[2]).test(method.name);
113+
} else {
114+
matching = methodsOrder[i] === method.name;
115+
}
116+
if (matching) {
117+
indexes.push(i);
118+
}
104119
}
105120
}
106121

@@ -109,6 +124,7 @@ module.exports = Components.detect(function(context, components) {
109124
for (i = 0, j = methodsOrder.length; i < j; i++) {
110125
if (methodsOrder[i] === 'everything-else') {
111126
indexes.push(i);
127+
break;
112128
}
113129
}
114130
}
@@ -127,7 +143,6 @@ module.exports = Components.detect(function(context, components) {
127143
* @returns {String} Property name.
128144
*/
129145
function getPropertyName(node) {
130-
131146
// Special case for class properties
132147
// (babel-eslint does not expose property name so we have to rely on tokens)
133148
if (node.type === 'ClassProperty') {
@@ -240,12 +255,12 @@ module.exports = Components.detect(function(context, components) {
240255

241256
/**
242257
* Compare two properties and find out if they are in the right order
243-
* @param {Array} propertiesNames Array containing all the properties names.
244-
* @param {String} propA First property name.
245-
* @param {String} propB Second property name.
258+
* @param {Array} propertiesInfos Array containing all the properties metadata.
259+
* @param {Object} propA First property name and metadata
260+
* @param {Object} propB Second property name.
246261
* @returns {Object} Object containing a correct true/false flag and the correct indexes for the two properties.
247262
*/
248-
function comparePropsOrder(propertiesNames, propA, propB) {
263+
function comparePropsOrder(propertiesInfos, propA, propB) {
249264
var i;
250265
var j;
251266
var k;
@@ -258,8 +273,8 @@ module.exports = Components.detect(function(context, components) {
258273
var refIndexesB = getRefPropIndexes(propB);
259274

260275
// Get current indexes for given properties
261-
var classIndexA = propertiesNames.indexOf(propA);
262-
var classIndexB = propertiesNames.indexOf(propB);
276+
var classIndexA = propertiesInfos.indexOf(propA);
277+
var classIndexB = propertiesInfos.indexOf(propB);
263278

264279
// Loop around the references indexes for the 1st property
265280
for (i = 0, j = refIndexesA.length; i < j; i++) {
@@ -300,7 +315,13 @@ module.exports = Components.detect(function(context, components) {
300315
* @param {Array} properties Array containing all the properties.
301316
*/
302317
function checkPropsOrder(properties) {
303-
var propertiesNames = properties.map(getPropertyName);
318+
var propertiesInfos = properties.map(function(node) {
319+
return {
320+
name: getPropertyName(node),
321+
static: node.static
322+
};
323+
});
324+
304325
var i;
305326
var j;
306327
var k;
@@ -310,15 +331,15 @@ module.exports = Components.detect(function(context, components) {
310331
var order;
311332

312333
// Loop around the properties
313-
for (i = 0, j = propertiesNames.length; i < j; i++) {
314-
propA = propertiesNames[i];
334+
for (i = 0, j = propertiesInfos.length; i < j; i++) {
335+
propA = propertiesInfos[i];
315336

316337
// Loop around the properties a second time (for comparison)
317-
for (k = 0, l = propertiesNames.length; k < l; k++) {
318-
propB = propertiesNames[k];
338+
for (k = 0, l = propertiesInfos.length; k < l; k++) {
339+
propB = propertiesInfos[k];
319340

320341
// Compare the properties order
321-
order = comparePropsOrder(propertiesNames, propA, propB);
342+
order = comparePropsOrder(propertiesInfos, propA, propB);
322343

323344
// Continue to next comparison is order is correct
324345
if (order.correct === true) {

0 commit comments

Comments
 (0)