license import * as Lint from "tslint" ; import { isJsxAttribute , isJsxExpression } from "tsutils/typeguard/3.0" ; import * as ts from "typescript" ; export class Rule extends Lint . Rules . AbstractRule { public static metadata : Lint . IRuleMetadata = { ruleName : "jsx-no-lambda" , description : "Checks for fresh lambda literals used in JSX attributes" , descriptionDetails : Lint . Utils . dedent `Creating new anonymous functions (with either the function syntax or \
            ES2015 arrow syntax) inside the render call stack works against pure component \
            rendering. When doing an equality check between two lambdas, React will always \
            consider them unequal values and force the component to re-render more often than necessary.` , options : null , optionsDescription : "" , optionExamples : [ "true" ] , type : "functionality" , typescriptOnly : false , } ; public static FAILURE_STRING = "Lambdas are forbidden in JSX attributes due to their rendering performance impact" ; public apply ( sourceFile ) { return this . applyWithFunction ( sourceFile , walk ) ; } } function walk ( ctx ) { return ts . forEachChild ( ctx . sourceFile , function cb ( node ) : void { if ( isJsxAttribute ( node ) ) { const { initializer } = node ; if ( initializer === undefined || ! isJsxExpression ( initializer ) ) { return ; } if ( node . name . text === "ref" ) { return ; } const { expression } = initializer ; if ( expression !== undefined && isLambda ( expression ) ) { return ctx . addFailureAtNode ( expression , Rule . FAILURE_STRING ) ; } } return ts . forEachChild ( node , cb ) ; } ) ; } function isLambda ( node ) { switch ( node . kind ) { case ts . SyntaxKind . FunctionExpression : case ts . SyntaxKind . ArrowFunction : return true ; case ts . SyntaxKind . ParenthesizedExpression : return isLambda ( ( node as ts . ParenthesizedExpression ) . expression ) ; default : return false ; } }