-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Add no-deprecated-methods
rule to prevents usage of deprecated component lifecycle methods
#1748
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
Changes from 3 commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
12d1376
Added `no-component-will-receive-props` rule
sergei-startsev daa076f
`no-component-will-receive-props` => `no-deprecated-methods`, added docs
sergei-startsev 5c7ab5f
Fixed jsdoc comments for `no-deprecated-methods` rule
sergei-startsev 323dba2
Adjusted no-deprecated rule for React 16.3.0
sergei-startsev c8008e0
Merge remote-tracking branch 'origin/master'
sergei-startsev 69b1317
Fix default-props-match-prop-types type annotations detection with ES…
yannickcr 31e4f33
Fix require-default-props type annotations detection with ESLint 3
yannickcr 677e1bd
Fix jsx-sort-props auto fix with ESLint 3
yannickcr cb4d21e
Run tests against different ESLint versions on Travis
yannickcr 589231a
Add SpreadElement support to boolean-prop-naming
yannickcr e6e8955
Add SpreadElement support to default-props-match-prop-types
yannickcr 3762258
Add JSXText support to jsx-child-element-spacing
yannickcr c734901
Add JSXText support to jsx-curly-brace-presence
yannickcr 0a6cb51
Add JSXText support to jsx-indent
yannickcr bd6caf0
Add JSXText support to jsx-no-literals
yannickcr 0a028e4
Add JSXText support to jsx-one-expression-per-line
yannickcr ed3370b
Add SpreadElement and JSXText support to no-danger-with-children
yannickcr ce1fec7
Add JSXText support to no-unescaped-entities
yannickcr b3ed9d6
Add SpreadElement and RestElement support to no-unused-state
yannickcr 632941c
Add SpreadElement support to require-default-props
yannickcr 29c248d
Add JSXText support to self-closing-comp
yannickcr f2d8729
Add SpreadElement support to sort-prop-types
yannickcr 9d4e27a
Ignore no-typos test that only works with ESLint 5
yannickcr ab6b41a
Remove deprecated experimentalObjectRestSpread option from tests conf…
yannickcr 0d34198
Update CHANGELOG and bump version
yannickcr 9e83b7c
[Deps] update `has`, `prop-types`, `doctrine`
ljharb df430ee
[Dev Deps] update `babel-eslint`, `coveralls`, `eslint`, `mocha`
ljharb ac10288
Update CHANGELOG and bump version
ljharb 7c5b8c4
[Docs] Typo fixes in jsx-no-target-blank
ferhatelmas d779865
Merge pull request #1805 from ferhatelmas/patch-1
ljharb fee2d1a
Fix crash in no-unused-prop-types when encountering mixed union and i…
yannickcr c82746c
Fix crash in no-unused-prop-types when encountering impossible inters…
yannickcr fcff54e
Allow LHS in destructuring-assignment
alexzherdev b6e911b
Remove unnecessary babel-eslint
alexzherdev f924414
Fix static propTypes handling in no-typos
alexzherdev 2a674b0
Merge pull request #1825 from alexzherdev/1728-destructuring-state-as…
ljharb d68b9e8
Remove unnecessary babel-eslint and fix typo
alexzherdev 48e386d
Merge pull request #1827 from alexzherdev/1677-no-typos-static-proptypes
ljharb 278e76a
Merge remote-tracking branch 'origin/master'
sergei-startsev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# Prevents usage of deprecated component lifecycle methods (react/no-deprecated-methods) | ||
|
||
Warns if you have deprecated methods defined when defining a component that extends `React.Component`, `React.PureComponent` or uses ES5 syntax with `createReactClass`. See [React 16.3 details](https://reactjs.org/blog/2018/03/27/update-on-async-rendering.html#gradual-migration-path). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Phrasing could be improved. |
||
|
||
## Rule Details | ||
|
||
The following patterns are considered warnings: | ||
|
||
```jsx | ||
class Foo extends React.Component { | ||
componentWillReceiveProps() { } | ||
// ... | ||
} | ||
|
||
class Foo extends React.PureComponent { | ||
componentWillReceiveProps() { } | ||
// ... | ||
} | ||
|
||
var Foo = createReactClass({ | ||
componentWillReceiveProps: function() {}, | ||
}) | ||
``` | ||
|
||
The following patterns are **not** considered warnings: | ||
|
||
```jsx | ||
class Foo { | ||
componentWillReceiveProps() {} | ||
} | ||
|
||
var Foo = createReactClassNonReact({ | ||
componentWillReceiveProps: function() {} | ||
}); | ||
``` | ||
|
||
## Rule Options | ||
|
||
This rule can take options to ignore some deprecated methods. | ||
|
||
```js | ||
... | ||
"react/no-deprecated-methods": [<enabled>, { | ||
"componentWillMount": <boolean>, | ||
"componentWillReceiveProps": <boolean>, | ||
"componentWillUpdate": <boolean>, | ||
}] | ||
... | ||
``` | ||
|
||
* `componentWillMount`: `true` by default. | ||
* `componentWillReceiveProps`: `true` by default. | ||
* `componentWillUpdate`: `true` by default. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
/** | ||
* @fileoverview Prevents usage of deprecated component lifecycle methods | ||
*/ | ||
'use strict'; | ||
|
||
const Components = require('../util/Components'); | ||
const astUtil = require('../util/ast'); | ||
const docsUrl = require('../util/docsUrl'); | ||
|
||
function errorMessage(node, method) { | ||
return `${node} should not use ${method}.`; | ||
} | ||
|
||
// ------------------------------------------------------------------------------ | ||
// Rule Definition | ||
// ------------------------------------------------------------------------------ | ||
|
||
module.exports = { | ||
meta: { | ||
docs: { | ||
description: 'Prevents usage of deprecated component lifecycle methods', | ||
category: 'Possible Errors', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
recommended: false, | ||
url: docsUrl('no-deprecated-methods') | ||
}, | ||
schema: [{ | ||
type: 'object', | ||
properties: { | ||
componentWillMount: { | ||
type: 'boolean' | ||
}, | ||
componentWillReceiveProps: { | ||
type: 'boolean' | ||
}, | ||
componentWillUpdate: { | ||
type: 'boolean' | ||
} | ||
}, | ||
additionalProperties: false | ||
}] | ||
}, | ||
|
||
create: Components.detect((context, components, utils) => { | ||
const defaults = { | ||
componentWillMount: true, | ||
componentWillReceiveProps: true, | ||
componentWillUpdate: true | ||
}; | ||
const configuration = Object.assign({}, defaults, context.options[0] || {}); | ||
const methods = Object.keys(configuration).filter(key => configuration[key]); | ||
/** | ||
* Returns deprecated methods if available | ||
* @param {ASTNode} node The AST node being checked. | ||
* @returns {Array} The array of deprecated methods. | ||
*/ | ||
function getDeprecatedMethods(node) { | ||
const properties = astUtil.getComponentProperties(node); | ||
return properties | ||
.map(property => astUtil.getPropertyName(property)) | ||
.filter(name => methods.indexOf(name) !== -1); | ||
} | ||
|
||
/** | ||
* Gets name of node if available | ||
* @param {ASTNode} node The AST node being checked. | ||
* @return {String} The name of the node | ||
*/ | ||
function getNodeName(node) { | ||
if (node.id) { | ||
return node.id.name; | ||
} else if (node.parent && node.parent.id) { | ||
return node.parent.id.name; | ||
} else if (node.parent && node.parent.parent && node.parent.parent.id) { | ||
return node.parent.parent.id.name; | ||
} | ||
return ''; | ||
} | ||
|
||
/** | ||
* Checks for violation of rule | ||
* @param {ASTNode} node The AST node being checked. | ||
*/ | ||
function checkForViolation(node) { | ||
if (utils.isES5Component(node) || utils.isES6Component(node)) { | ||
const deprecatedMethods = getDeprecatedMethods(node); | ||
if (deprecatedMethods && deprecatedMethods.length) { | ||
const className = getNodeName(node); | ||
deprecatedMethods.forEach(method => { | ||
context.report({ | ||
node: node, | ||
message: errorMessage(className, method) | ||
}); | ||
}); | ||
} | ||
} | ||
} | ||
|
||
return { | ||
ClassDeclaration: checkForViolation, | ||
ClassExpression: checkForViolation, | ||
ObjectExpression: checkForViolation | ||
}; | ||
}) | ||
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,222 @@ | ||
/** | ||
* @fileoverview Tests for no-deprecated-methods | ||
*/ | ||
|
||
'use strict'; | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Requirements | ||
// ----------------------------------------------------------------------------- | ||
|
||
const rule = require('../../../lib/rules/no-deprecated-methods'); | ||
const RuleTester = require('eslint').RuleTester; | ||
|
||
const parserOptions = { | ||
ecmaVersion: 6, | ||
ecmaFeatures: { | ||
experimentalObjectRestSpread: true, | ||
jsx: true | ||
} | ||
}; | ||
|
||
function errorMessage(node, method) { | ||
return `${node} should not use ${method}.`; | ||
} | ||
|
||
// ----------------------------------------------------------------------------- | ||
// Tests | ||
// ----------------------------------------------------------------------------- | ||
|
||
const ruleTester = new RuleTester(); | ||
ruleTester.run('no-deprecated-methods', rule, { | ||
valid: [ | ||
{ | ||
code: ` | ||
var Foo = createReactClass({ | ||
render: function() {} | ||
}) | ||
`, | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
var Foo = createReactClassNonReact({ | ||
componentWillMount: function() {}, | ||
componentWillReceiveProps: function() {}, | ||
componentWillUpdate: function() {} | ||
}); | ||
`, | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
var Foo = { | ||
componentWillMount: function() {}, | ||
componentWillReceiveProps: function() {}, | ||
componentWillUpdate: function() {} | ||
}; | ||
`, | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo { | ||
componentWillMount() {} | ||
componentWillReceiveProps() {} | ||
componentWillUpdate() {} | ||
} | ||
`, | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo extends React.Component { | ||
} | ||
`, | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo extends React.Component { | ||
} | ||
`, | ||
parser: 'babel-eslint', | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo extends React.PureComponent { | ||
} | ||
`, | ||
parser: 'babel-eslint', | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
function Foo() { | ||
return class Bar extends React.Component { | ||
}; | ||
} | ||
`, | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
function Foo() { | ||
return <div>test</div> | ||
} | ||
`, | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo extends React.Component { | ||
componentWillMount() {} | ||
componentWillReceiveProps() {} | ||
componentWillUpdate() {} | ||
} | ||
`, | ||
options: [{ | ||
componentWillMount: false, | ||
componentWillReceiveProps: false, | ||
componentWillUpdate: false | ||
}], | ||
parserOptions: parserOptions | ||
} | ||
], | ||
|
||
invalid: [ | ||
{ | ||
code: ` | ||
function Foo() { | ||
return class Bar extends React.PureComponent { | ||
componentWillMount() {} | ||
componentWillReceiveProps() {} | ||
componentWillUpdate() {} | ||
}; | ||
} | ||
`, | ||
errors: [ | ||
{message: errorMessage('Bar', 'componentWillMount')}, | ||
{message: errorMessage('Bar', 'componentWillReceiveProps')}, | ||
{message: errorMessage('Bar', 'componentWillUpdate')} | ||
], | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
var Foo = createReactClass({ | ||
componentWillMount: function() {}, | ||
componentWillReceiveProps: function() {}, | ||
componentWillUpdate: function() {} | ||
}) | ||
`, | ||
errors: [ | ||
{message: errorMessage('Foo', 'componentWillMount')}, | ||
{message: errorMessage('Foo', 'componentWillReceiveProps')}, | ||
{message: errorMessage('Foo', 'componentWillUpdate')} | ||
], | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo extends React.PureComponent { | ||
componentWillMount() {} | ||
componentWillReceiveProps() {} | ||
componentWillUpdate() {} | ||
} | ||
`, | ||
errors: [ | ||
{message: errorMessage('Foo', 'componentWillMount')}, | ||
{message: errorMessage('Foo', 'componentWillReceiveProps')}, | ||
{message: errorMessage('Foo', 'componentWillUpdate')} | ||
], | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo extends PureComponent { | ||
componentWillMount() {} | ||
componentWillReceiveProps() {} | ||
componentWillUpdate() {} | ||
} | ||
`, | ||
errors: [ | ||
{message: errorMessage('Foo', 'componentWillMount')}, | ||
{message: errorMessage('Foo', 'componentWillReceiveProps')}, | ||
{message: errorMessage('Foo', 'componentWillUpdate')} | ||
], | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo extends React.Component { | ||
componentWillMount() {} | ||
componentWillReceiveProps() {} | ||
componentWillUpdate() {} | ||
} | ||
`, | ||
errors: [ | ||
{message: errorMessage('Foo', 'componentWillMount')}, | ||
{message: errorMessage('Foo', 'componentWillReceiveProps')}, | ||
{message: errorMessage('Foo', 'componentWillUpdate')} | ||
], | ||
parserOptions: parserOptions | ||
}, | ||
{ | ||
code: ` | ||
class Foo extends Component { | ||
componentWillMount() {} | ||
componentWillReceiveProps() {} | ||
componentWillUpdate() {} | ||
} | ||
`, | ||
errors: [ | ||
{message: errorMessage('Foo', 'componentWillMount')}, | ||
{message: errorMessage('Foo', 'componentWillReceiveProps')}, | ||
{message: errorMessage('Foo', 'componentWillUpdate')} | ||
], | ||
parserOptions: parserOptions | ||
} | ||
] | ||
}); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be added to
no-deprecated
; since that rule already deals with methods, including lifecycle methods.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could please point to an example of life cycle method in
no-deprecated
? I couldn't find any...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There may not be an existing example, but the rule still deals with any depreciations - otherwise it’d be called no-deprecated-static or something :-)