diff --git a/lib/rules/sort-comp.js b/lib/rules/sort-comp.js index 4e2602a74e..f788f18993 100644 --- a/lib/rules/sort-comp.js +++ b/lib/rules/sort-comp.js @@ -47,7 +47,8 @@ const defaultConfig = { 'componentDidCatch', 'componentWillUnmount' ] - } + }, + preferLifecycle: false }; /** @@ -56,8 +57,6 @@ const defaultConfig = { * @returns {Array} Methods order */ function getMethodsOrder(userConfig) { - userConfig = userConfig || {}; - const groups = util._extend(defaultConfig.groups, userConfig.groups); const order = userConfig.order || defaultConfig.order; @@ -75,6 +74,19 @@ function getMethodsOrder(userConfig) { return config; } +/** + * Returns a function that checks if the method name is a lifecycle method + * @param {Object} userConfig The user configuration. + * @returns {Function} isLifecycle + */ +function makeIsLifecycle(userConfig) { + const groups = util._extend(defaultConfig.groups, userConfig.groups); + const lifecycleGroup = groups.lifecycle || []; + return function isLifecycle(methodName) { + return arrayIncludes(lifecycleGroup, methodName); + }; +} + // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ @@ -107,6 +119,10 @@ module.exports = { } } } + }, + preferLifecycle: { + type: 'boolean', + default: defaultConfig.default } }, additionalProperties: false @@ -118,7 +134,10 @@ module.exports = { const MISPOSITION_MESSAGE = '{{propA}} should be placed {{position}} {{propB}}'; - const methodsOrder = getMethodsOrder(context.options[0]); + const userConfig = context.options[0] || {}; + const methodsOrder = getMethodsOrder(userConfig); + const isLifecycle = makeIsLifecycle(userConfig); + const preferLifecycle = userConfig.preferLifecycle || defaultConfig.preferLifecycle; // -------------------------------------------------------------------------- // Public @@ -149,7 +168,9 @@ module.exports = { } } else if (currentGroup === 'static-methods') { if (method.static) { - methodGroupIndexes.push(groupIndex); + if (!(preferLifecycle && isLifecycle(method.name))) { + methodGroupIndexes.push(groupIndex); + } } } else if (currentGroup === 'instance-variables') { if (method.instanceVariable) { @@ -159,34 +180,7 @@ module.exports = { if (method.instanceMethod) { methodGroupIndexes.push(groupIndex); } - } else if (arrayIncludes([ - 'displayName', - 'propTypes', - 'contextTypes', - 'childContextTypes', - 'mixins', - 'statics', - 'defaultProps', - 'constructor', - 'getDefaultProps', - 'state', - 'getInitialState', - 'getChildContext', - 'getDerivedStateFromProps', - 'componentWillMount', - 'UNSAFE_componentWillMount', - 'componentDidMount', - 'componentWillReceiveProps', - 'UNSAFE_componentWillReceiveProps', - 'shouldComponentUpdate', - 'componentWillUpdate', - 'UNSAFE_componentWillUpdate', - 'getSnapshotBeforeUpdate', - 'componentDidUpdate', - 'componentDidCatch', - 'componentWillUnmount', - 'render' - ], currentGroup)) { + } else if (isLifecycle(currentGroup) || currentGroup === 'render') { if (currentGroup === method.name) { methodGroupIndexes.push(groupIndex); } diff --git a/tests/lib/rules/sort-comp.js b/tests/lib/rules/sort-comp.js index 8277b10ab3..59f9c89412 100644 --- a/tests/lib/rules/sort-comp.js +++ b/tests/lib/rules/sort-comp.js @@ -468,7 +468,7 @@ ruleTester.run('sort-comp', rule, { }] }, { code: [ - '// static lifecycle methods can be grouped (with statics)', + '// by default static lifecycle methods can be grouped with static', 'class Hello extends React.Component {', ' static getDerivedStateFromProps() {}', ' constructor() {}', @@ -476,12 +476,13 @@ ruleTester.run('sort-comp', rule, { ].join('\n') }, { code: [ - '// static lifecycle methods can be grouped (with lifecycle)', + '// static lifecycle methods should be grouped under lifecycle with the preferLifecycle set to true', 'class Hello extends React.Component {', ' constructor() {}', ' static getDerivedStateFromProps() {}', '}' - ].join('\n') + ].join('\n'), + options: [{preferLifecycle: true}] }], invalid: [{ @@ -766,5 +767,15 @@ ruleTester.run('sort-comp', rule, { 'render' ] }] + }, { + code: [ + '// static lifecycle methods should warn if not grouped under the lifecycle group', + 'class Hello extends React.Component {', + ' static getDerivedStateFromProps() {}', + ' constructor() {}', + '}' + ].join('\n'), + errors: [{message: 'getDerivedStateFromProps should be placed after constructor'}], + options: [{preferLifecycle: true}] }] });