require_optimization

package
v0.5.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 14, 2026 License: MIT Imports: 5 Imported by: 0

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

type Options

type Options struct {
	AllowDecorators []string
}

Options mirrors upstream's schema:

[{
  type: 'object',
  properties: {
    allowDecorators: {
      type: 'array',
      items: { type: 'string' },
    },
  },
  additionalProperties: false,
}]

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL