diff --git a/lib/rules/no-arrow-function-lifecycle.js b/lib/rules/no-arrow-function-lifecycle.js index 6a771ec57e..1e8cebc7ca 100644 --- a/lib/rules/no-arrow-function-lifecycle.js +++ b/lib/rules/no-arrow-function-lifecycle.js @@ -23,22 +23,40 @@ module.exports = { }, create: Components.detect((context, components) => { + function getText(node) { + const params = node.value.params.map((p) => p.name); + + if (node.type === 'Property') { + return `: function(${params.join(', ')}) `; + } + + if (node.type === 'ClassProperty') { + return `(${params.join(', ')}) `; + } + + return null; + } + /** * @param {Array} properties list of component properties */ function reportNoArrowFunctionLifecycle(properties) { properties.forEach((node) => { const propertyName = astUtil.getPropertyName(node); - const nodeType = node.value && node.value.type; + const nodeType = node.value.type; const isLifecycleMethod = lifecycleMethods.includes(propertyName); if (nodeType === 'ArrowFunctionExpression' && isLifecycleMethod) { + const range = [node.key.range[1], node.value.body.range[0]]; + const text = getText(node); + context.report({ node, message: '{{propertyName}} is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.', data: { propertyName - } + }, + fix: (fixer) => fixer.replaceTextRange(range, text) }); } }); diff --git a/lib/rules/no-typos.js b/lib/rules/no-typos.js index e2007afada..8e9ef094e7 100644 --- a/lib/rules/no-typos.js +++ b/lib/rules/no-typos.js @@ -163,7 +163,7 @@ module.exports = { } }); - lifecycleMethods.forEach(method => { + lifecycleMethods.forEach((method) => { if (method.toLowerCase() === nodeKeyName.toLowerCase() && method !== nodeKeyName) { context.report({ node, diff --git a/tests/lib/rules/no-arrow-function-lifecycle.js b/tests/lib/rules/no-arrow-function-lifecycle.js index 59629aada3..fa3f96c38e 100644 --- a/tests/lib/rules/no-arrow-function-lifecycle.js +++ b/tests/lib/rules/no-arrow-function-lifecycle.js @@ -340,7 +340,12 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + render: function() { return
; } + }); + ` }, { code: ` @@ -351,7 +356,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'getDefaultProps is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + getDefaultProps: function() { return {}; }, + render: function() { return
; } + }); + ` }, { code: ` @@ -362,7 +373,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'getInitialState is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + getInitialState: function() { return {}; }, + render: function() { return
; } + }); + ` }, { code: ` @@ -373,7 +390,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'getChildContext is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + getChildContext: function() { return {}; }, + render: function() { return
; } + }); + ` }, { code: ` @@ -384,7 +407,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'getDerivedStateFromProps is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + getDerivedStateFromProps: function() { return {}; }, + render: function() { return
; } + }); + ` }, { code: ` @@ -395,7 +424,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'componentWillMount is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + componentWillMount: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -406,7 +441,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'UNSAFE_componentWillMount is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + UNSAFE_componentWillMount: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -417,7 +458,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'componentDidMount is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + componentDidMount: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -428,7 +475,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'componentWillReceiveProps is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + componentWillReceiveProps: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -439,7 +492,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'UNSAFE_componentWillReceiveProps is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + UNSAFE_componentWillReceiveProps: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -450,7 +509,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'shouldComponentUpdate is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + shouldComponentUpdate: function() { return true; }, + render: function() { return
; } + }); + ` }, { code: ` @@ -461,7 +526,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'componentWillUpdate is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + componentWillUpdate: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -472,7 +543,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'UNSAFE_componentWillUpdate is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + UNSAFE_componentWillUpdate: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -483,7 +560,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'getSnapshotBeforeUpdate is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + getSnapshotBeforeUpdate: function() { return {}; }, + render: function() { return
; } + }); + ` }, { code: ` @@ -494,7 +577,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'componentDidUpdate is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + componentDidUpdate: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -505,7 +594,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'componentDidCatch is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + componentDidCatch: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -516,7 +611,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { `, errors: [{ message: 'componentWillUnmount is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + var Hello = createReactClass({ + componentWillUnmount: function() {}, + render: function() { return
; } + }); + ` }, { code: ` @@ -528,7 +629,13 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { parser: parsers.BABEL_ESLINT, errors: [{ message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + render() { return
; } + } + ` }, { code: ` @@ -544,7 +651,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + getDefaultProps() { return {}; } + render() { return
; } + } + ` }, { code: ` @@ -560,7 +674,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + getInitialState() { return {}; } + render() { return
; } + } + ` }, { code: ` @@ -576,7 +697,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + getChildContext() { return {}; } + render() { return
; } + } + ` }, { code: ` @@ -592,7 +720,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + getDerivedStateFromProps() { return {}; } + render() { return
; } + } + ` }, { code: ` @@ -608,7 +743,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + componentWillMount() {} + render() { return
; } + } + ` }, { code: ` @@ -624,7 +766,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + UNSAFE_componentWillMount() {} + render() { return
; } + } + ` }, { code: ` @@ -640,7 +789,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + componentDidMount() {} + render() { return
; } + } + ` }, { code: ` @@ -656,7 +812,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + componentWillReceiveProps() {} + render() { return
; } + } + ` }, { code: ` @@ -672,7 +835,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + UNSAFE_componentWillReceiveProps() {} + render() { return
; } + } + ` }, { code: ` @@ -688,7 +858,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + shouldComponentUpdate() { return true; } + render() { return
; } + } + ` }, { code: ` @@ -704,7 +881,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + componentWillUpdate() {} + render() { return
; } + } + ` }, { code: ` @@ -720,7 +904,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + UNSAFE_componentWillUpdate() {} + render() { return
; } + } + ` }, { code: ` @@ -736,7 +927,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + getSnapshotBeforeUpdate() { return {}; } + render() { return
; } + } + ` }, { code: ` @@ -752,7 +950,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + componentDidUpdate(prevProps) {} + render() { return
; } + } + ` }, { code: ` @@ -768,7 +973,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + componentDidCatch() {} + render() { return
; } + } + ` }, { code: ` @@ -784,7 +996,14 @@ ruleTester.run('no-arrow-function-lifecycle', rule, { }, { message: 'render is a React lifecycle method, and should not be an arrow function or in a class field. Use an instance method instead.' - }] + }], + output: ` + class Hello extends React.Component { + handleEventMethods = () => {} + componentWillUnmount() {} + render() { return
; } + } + ` } ] });