Skip to content

Commit 3a8bf42

Browse files
dozoischyannickcr
authored andcommitted
Add support for typeAnnotations in sort-comp (fixes jsx-eslint#235)
1 parent 055ea4d commit 3a8bf42

File tree

3 files changed

+159
-1
lines changed

3 files changed

+159
-1
lines changed

docs/rules/sort-comp.md

+43
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ The default configuration is:
8989
* `lifecycle` is referring to the `lifecycle` group defined in `groups`.
9090
* `everything-else` is a special group that match all the methods that do not match any of the other groups.
9191
* `render` is referring to the `render` method.
92+
* `type-annotations`. This group is not speficied by default, but can be used enforce flow annotations to be at the top.
9293

9394
You can override this configuration to match your needs.
9495

@@ -171,6 +172,48 @@ var Hello = React.createClass({
171172
});
172173
```
173174

175+
If you want to flow annotations to be at the top:
176+
177+
```js
178+
"react/sort-comp": [1, {
179+
order: [
180+
'type-annotations',
181+
'static-methods',
182+
'lifecycle',
183+
'everything-else',
184+
'render',
185+
],
186+
}]
187+
```
188+
189+
With the above configuration, the following patterns are considered warnings:
190+
191+
```js
192+
class Hello extends React.Component<any, Props, void> {
193+
onClick() { this._someElem = true; }
194+
props: Props;
195+
_someElem: bool;
196+
render() {
197+
return <div>Hello</div>;
198+
}
199+
}
200+
```
201+
202+
With the above configuration, the following patterns are not considered warnings:
203+
204+
```js
205+
type Props = {};
206+
class Hello extends React.Component<any, Props, void> {
207+
props: Props;
208+
_someElem: bool;
209+
onClick() { this._someElem = true; }
210+
render() {
211+
return <div>Hello</div>;
212+
}
213+
}
214+
```
215+
216+
174217
## When Not To Use It
175218

176219
This rule is a formatting preference and not following it won't negatively affect the quality of your code. If components organisation isn't a part of your coding standards, then you can leave this rule off.

lib/rules/sort-comp.js

+11-1
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,15 @@ module.exports = {
136136
}
137137
}
138138

139+
if (method.typeAnnotation) {
140+
for (i = 0, j = methodsOrder.length; i < j; i++) {
141+
if (methodsOrder[i] === 'type-annotations') {
142+
indexes.push(i);
143+
break;
144+
}
145+
}
146+
}
147+
139148
// Either this is not a static method or static methods are not specified
140149
// in the methodsOrder.
141150
if (indexes.length === 0) {
@@ -353,7 +362,8 @@ module.exports = {
353362
var propertiesInfos = properties.map(function(node) {
354363
return {
355364
name: getPropertyName(node),
356-
static: node.static
365+
static: node.static,
366+
typeAnnotation: !!node.typeAnnotation && node.value === null
357367
};
358368
});
359369

tests/lib/rules/sort-comp.js

+105
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,51 @@ ruleTester.run('sort-comp', rule, {
203203
'});'
204204
].join('\n'),
205205
parser: 'babel-eslint'
206+
}, {
207+
// Type Annotations should be first
208+
code: [
209+
'class Hello extends React.Component {',
210+
' props: { text: string };',
211+
' constructor() {}',
212+
' render() {',
213+
' return <div>{this.props.text}</div>;',
214+
' }',
215+
'}'
216+
].join('\n'),
217+
parser: 'babel-eslint',
218+
parserOptions: parserOptions,
219+
options: [{
220+
order: [
221+
'type-annotations',
222+
'static-methods',
223+
'lifecycle',
224+
'everything-else',
225+
'render'
226+
]
227+
}]
228+
}, {
229+
// Properties with Type Annotations should not be at the top
230+
code: [
231+
'class Hello extends React.Component {',
232+
' props: { text: string };',
233+
' constructor() {}',
234+
' state: Object = {};',
235+
' render() {',
236+
' return <div>{this.props.text}</div>;',
237+
' }',
238+
'}'
239+
].join('\n'),
240+
parser: 'babel-eslint',
241+
parserOptions: parserOptions,
242+
options: [{
243+
order: [
244+
'type-annotations',
245+
'static-methods',
246+
'lifecycle',
247+
'everything-else',
248+
'render'
249+
]
250+
}]
206251
}],
207252

208253
invalid: [{
@@ -273,5 +318,65 @@ ruleTester.run('sort-comp', rule, {
273318
parser: 'babel-eslint',
274319
parserOptions: parserOptions,
275320
errors: [{message: 'render should be placed after displayName'}]
321+
}, {
322+
// Type Annotations should not be at the top by default
323+
code: [
324+
'class Hello extends React.Component {',
325+
' props: { text: string };',
326+
' constructor() {}',
327+
' state: Object = {};',
328+
' render() {',
329+
' return <div>{this.props.text}</div>;',
330+
' }',
331+
'}'
332+
].join('\n'),
333+
parser: 'babel-eslint',
334+
parserOptions: parserOptions,
335+
errors: [{message: 'props should be placed after state'}]
336+
}, {
337+
// Type Annotations should be first
338+
code: [
339+
'class Hello extends React.Component {',
340+
' constructor() {}',
341+
' props: { text: string };',
342+
' render() {',
343+
' return <div>{this.props.text}</div>;',
344+
' }',
345+
'}'
346+
].join('\n'),
347+
parser: 'babel-eslint',
348+
errors: [{message: 'constructor should be placed after props'}],
349+
options: [{
350+
order: [
351+
'type-annotations',
352+
'static-methods',
353+
'lifecycle',
354+
'everything-else',
355+
'render'
356+
]
357+
}]
358+
}, {
359+
// Properties with Type Annotations should not be at the top
360+
code: [
361+
'class Hello extends React.Component {',
362+
' props: { text: string };',
363+
' state: Object = {};',
364+
' constructor() {}',
365+
' render() {',
366+
' return <div>{this.props.text}</div>;',
367+
' }',
368+
'}'
369+
].join('\n'),
370+
parser: 'babel-eslint',
371+
errors: [{message: 'state should be placed after constructor'}],
372+
options: [{
373+
order: [
374+
'type-annotations',
375+
'static-methods',
376+
'lifecycle',
377+
'everything-else',
378+
'render'
379+
]
380+
}]
276381
}]
277382
});

0 commit comments

Comments
 (0)