diff --git a/docs/rules/sort-comp.md b/docs/rules/sort-comp.md index c1ec19b0bb..49fc85f9bd 100644 --- a/docs/rules/sort-comp.md +++ b/docs/rules/sort-comp.md @@ -89,9 +89,11 @@ The default configuration is: * `lifecycle` is referring to the `lifecycle` group defined in `groups`. * `everything-else` is a special group that match all the methods that do not match any of the other groups. * `render` is referring to the `render` method. -* `type-annotations`. This group is not specified by default, but can be used to enforce flow annotations to be at the top. +* `type-annotations`. This group is not specified by default, but can be used to enforce flow annotations positioning. * `getters` This group is not specified by default, but can be used to enforce class getters positioning. * `setters` This group is not specified by default, but can be used to enforce class setters positioning. +* `instance-variables` This group is not specified by default, but can be used to enforce all other instance variables positioning. +* `instance-methods` This group is not specified by default, but can be used to enforce all other instance methods positioning. You can override this configuration to match your needs. diff --git a/lib/rules/sort-comp.js b/lib/rules/sort-comp.js index e214905081..acb6c8158f 100644 --- a/lib/rules/sort-comp.js +++ b/lib/rules/sort-comp.js @@ -171,6 +171,20 @@ module.exports = { } } + if (indexes.length === 0 && method.instanceVariable) { + const annotationIndex = methodsOrder.indexOf('instance-variables'); + if (annotationIndex >= 0) { + indexes.push(annotationIndex); + } + } + + if (indexes.length === 0 && method.instanceMethod) { + const annotationIndex = methodsOrder.indexOf('instance-methods'); + if (annotationIndex >= 0) { + indexes.push(annotationIndex); + } + } + // No matching pattern, return 'everything-else' index if (indexes.length === 0) { for (i = 0, j = methodsOrder.length; i < j; i++) { @@ -384,6 +398,16 @@ module.exports = { getter: node.kind === 'get', setter: node.kind === 'set', static: node.static, + instanceVariable: !node.static && + node.type === 'ClassProperty' && + node.value && + node.value.type !== 'ArrowFunctionExpression' && + node.value.type !== 'FunctionExpression', + instanceMethod: !node.static && + node.type === 'ClassProperty' && + node.value && + (node.value.type === 'ArrowFunctionExpression' || + node.value.type === 'FunctionExpression'), typeAnnotation: !!node.typeAnnotation && node.value === null })); diff --git a/tests/lib/rules/sort-comp.js b/tests/lib/rules/sort-comp.js index df1944040e..ac9da200a3 100644 --- a/tests/lib/rules/sort-comp.js +++ b/tests/lib/rules/sort-comp.js @@ -310,6 +310,50 @@ ruleTester.run('sort-comp', rule, { 'render' ] }] + }, { + // Instance methods should be at the top + code: [ + 'class Hello extends React.Component {', + ' foo = () => {}', + ' constructor() {}', + ' classMethod() {}', + ' static bar = () => {}', + ' render() {', + ' return