Documentation
¶
Index ¶
Constants ¶
This section is empty.
Variables ¶
View Source
var RequireOptimizationRule = rule.Rule{ Name: "react/require-optimization", Run: func(ctx rule.RuleContext, options any) rule.RuleListeners { opts := parseOptions(options) pragma := reactutil.GetReactPragma(ctx.Settings) createClass := reactutil.GetReactCreateClass(ctx.Settings) msg := rule.RuleMessage{ Id: "noShouldComponentUpdate", Description: "Component is not optimized. Please add a shouldComponentUpdate method.", } detectionCache := make(map[*ast.Node]bool) isDetectedComponent := func(node *ast.Node) bool { if cached, ok := detectionCache[node]; ok { return cached } var result bool switch node.Kind { case ast.KindClassDeclaration, ast.KindClassExpression: result = reactutil.ExtendsReactComponent(node, pragma) case ast.KindObjectLiteralExpression: result = reactutil.IsCreateReactClassObjectArg(node, pragma, createClass) case ast.KindFunctionDeclaration, ast.KindFunctionExpression, ast.KindArrowFunction: if isInClassDeclarationMethodBody(node) { result = reactutil.IsStatelessReactComponentWithChecker(node, pragma, ctx.TypeChecker) } } detectionCache[node] = result return result } classSelfMarked := func(c *ast.Node) bool { if c.Kind != ast.KindClassDeclaration { return false } return hasPureRenderDecorator(c) || hasCustomDecorator(c, opts.AllowDecorators) || reactutil.ExtendsReactPureComponent(c, pragma) } // markedFromSubtree implements upstream's `mark-SCU-as-declared` walk-up // resolution: any markSCU source node (ObjectExpression with // SCU/PureRenderMixin, MethodDefinition with name SCU, ClassDeclaration // with PureRender / custom-allow decorator) inside `self`'s subtree // flows up the parent chain until it hits the nearest detected // component. We mirror that with a pre-order subtree scan that // PRUNES nested detected components — they would absorb the // markSCU themselves before it reaches `self`. // // Verified empirically against eslint-plugin-react@latest: // // class C extends React.Component { // init() { // const cfg = { shouldComponentUpdate() {} }; // marks C // } // } // not reported // // class Outer extends React.Component { // build() { // class Inner extends React.Component { scu() {} } // marks Inner // } // } // Outer reported var markedFromSubtree func(self *ast.Node, current *ast.Node) bool markedFromSubtree = func(self *ast.Node, current *ast.Node) bool { if current != self && isDetectedComponent(current) { return false } if current.Kind == ast.KindObjectLiteralExpression && objectDeclaresSCUOrMixin(current) { return true } if methodNameIsSCU(current) { return true } if current != self && current.Kind == ast.KindClassDeclaration { if hasPureRenderDecorator(current) || hasCustomDecorator(current, opts.AllowDecorators) { return true } } found := false current.ForEachChild(func(child *ast.Node) bool { if markedFromSubtree(self, child) { found = true return true } return false }) return found } report := func(c *ast.Node) { switch c.Kind { case ast.KindClassDeclaration, ast.KindClassExpression: start := reactutil.ClassKeywordStart(ctx.SourceFile.Text(), c) ctx.ReportRange(core.NewTextRange(start, c.End()), msg) default: ctx.ReportNode(c, msg) } } // Single-pass collect-and-resolve. Done eagerly here (instead of via // listeners + a SourceFile-exit hook) because rslint's visitor enters // the SourceFile's children directly — the SourceFile node itself is // never visited, so a `ListenerOnExit(KindSourceFile)` registration // would silently never fire. var collect func(*ast.Node) collect = func(n *ast.Node) { if n == nil { return } if isDetectedComponent(n) { if !classSelfMarked(n) && !markedFromSubtree(n, n) { report(n) } } n.ForEachChild(func(c *ast.Node) bool { collect(c) return false }) } ctx.SourceFile.Node.ForEachChild(func(n *ast.Node) bool { collect(n) return false }) return rule.RuleListeners{} }, }
Functions ¶
This section is empty.
Types ¶
Click to show internal directories.
Click to hide internal directories.