mirror of
https://github.com/desktop/desktop
synced 2024-08-24 02:42:15 +00:00
Add stub test for improper use of lifecycle methods
This commit is contained in:
parent
c72b8a1517
commit
b6bb413dcd
81
tslint-rules/reactProperLifecycleMethodsRule.ts
Normal file
81
tslint-rules/reactProperLifecycleMethodsRule.ts
Normal file
|
@ -0,0 +1,81 @@
|
|||
/**
|
||||
* react-proper-lifecycle-methods
|
||||
*
|
||||
* This custom tslint rule is attemptsto prevent erroneous usage of the React
|
||||
* lifecycle methods by ensuring proper method naming, and parameter order,
|
||||
* types and names.
|
||||
*
|
||||
*/
|
||||
|
||||
import * as ts from 'typescript'
|
||||
import * as Lint from 'tslint/lib/lint'
|
||||
|
||||
export class Rule extends Lint.Rules.AbstractRule {
|
||||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
|
||||
if (sourceFile.languageVariant === ts.LanguageVariant.JSX) {
|
||||
return this.applyWithWalker(new ReactProperLifecycleMethodsWalker(sourceFile, this.getOptions()))
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ReactProperLifecycleMethodsWalker extends Lint.RuleWalker {
|
||||
|
||||
private propsTypeName: string
|
||||
private stateTypeName: string
|
||||
|
||||
protected visitClassDeclaration(node: ts.ClassDeclaration): void {
|
||||
if (node.heritageClauses && node.heritageClauses.length) {
|
||||
for (const heritageClause of node.heritageClauses) {
|
||||
if (heritageClause.token === ts.SyntaxKind.ExtendsKeyword && heritageClause.types) {
|
||||
for (const type of heritageClause.types) {
|
||||
const inheritedName = type.expression.getText()
|
||||
|
||||
if (inheritedName === 'React.Component') {
|
||||
if (type.typeArguments && type.typeArguments.length === 2) {
|
||||
this.propsTypeName = type.typeArguments[0].getText()
|
||||
this.stateTypeName = type.typeArguments[1].getText()
|
||||
|
||||
console.log(this.propsTypeName, this.stateTypeName)
|
||||
|
||||
super.visitClassDeclaration(node)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected visitMethodDeclaration(node: ts.MethodDeclaration): void {
|
||||
const methodName = node.name.getText()
|
||||
if (/^component|^shouldComponent/.test(methodName)) {
|
||||
switch (methodName) {
|
||||
case 'componentWillMount':
|
||||
case 'componentDidMount':
|
||||
case 'componentWillUnmount':
|
||||
this.verifyEmptyParameters(node)
|
||||
break
|
||||
case 'componentWillReceiveProps':
|
||||
case 'shouldComponentUpdate':
|
||||
case 'componentWillUpdate':
|
||||
case 'componentDidUpdate':
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private verifyEmptyParameters(node: ts.MethodDeclaration) {
|
||||
if (node.parameters.length) {
|
||||
const start = node.getStart()
|
||||
const width = node.getWidth()
|
||||
|
||||
const methodName = node.name.getText()
|
||||
const message = `${methodName} should not accept any parameters.`
|
||||
|
||||
this.addFailure(this.createFailure(start, width, message))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@
|
|||
"single"
|
||||
],
|
||||
"react-no-unbound-dispatcher-props": true,
|
||||
"react-proper-lifecycle-methods": true,
|
||||
"react-readonly-props-and-state": true,
|
||||
"react-unused-props-and-state": [ true,
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue