jsx_no_bind

package
v0.19.0 Latest Latest
Warning

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

Go to latest
Published: Apr 26, 2026 License: MIT, MIT Imports: 4 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var JsxNoBindRule = rule.Rule{
	Name: "react/jsx-no-bind",
	Run: func(ctx rule.RuleContext, rawOptions any) rule.RuleListeners {
		opts := parseOptions(rawOptions)

		blockVariableNameSets := map[int]map[string]map[string]bool{}

		initBlock := func(blockPos int) {
			if _, ok := blockVariableNameSets[blockPos]; ok {
				return
			}
			blockVariableNameSets[blockPos] = map[string]map[string]bool{
				kindArrowFunc: {},
				kindBindCall:  {},
				kindFunc:      {},
			}
		}

		var getNodeViolationType func(node *ast.Node) string
		getNodeViolationType = func(node *ast.Node) string {
			node = unwrap(node)
			if node == nil {
				return ""
			}
			if !opts.allowBind && node.Kind == ast.KindCallExpression {
				callee := unwrap(node.AsCallExpression().Expression)
				if callee != nil && callee.Kind == ast.KindPropertyAccessExpression {
					nameNode := callee.AsPropertyAccessExpression().Name()
					if nameNode != nil && nameNode.Kind == ast.KindIdentifier && nameNode.AsIdentifier().Text == "bind" {
						return kindBindCall
					}
				}
			}
			if node.Kind == ast.KindConditionalExpression {
				ce := node.AsConditionalExpression()
				if t := getNodeViolationType(ce.Condition); t != "" {
					return t
				}
				if t := getNodeViolationType(ce.WhenTrue); t != "" {
					return t
				}
				return getNodeViolationType(ce.WhenFalse)
			}
			if !opts.allowArrowFunctions && node.Kind == ast.KindArrowFunction {
				return kindArrowFunc
			}
			if !opts.allowFunctions && (node.Kind == ast.KindFunctionExpression || node.Kind == ast.KindFunctionDeclaration) {
				return kindFunc
			}
			return ""
		}

		blockAncestors := func(node *ast.Node) []*ast.Node {
			var result []*ast.Node
			for cur := node.Parent; cur != nil; cur = cur.Parent {
				if cur.Kind == ast.KindBlock {
					result = append(result, cur)
				}
			}
			return result
		}

		reportVariableViolation := func(attrNode *ast.Node, name string, blockPos int) bool {
			sets, ok := blockVariableNameSets[blockPos]
			if !ok {
				return false
			}
			for _, violationType := range violationOrder {
				if sets[violationType][name] {
					ctx.ReportNode(attrNode, message(violationType))
					return true
				}
			}
			return false
		}

		findVariableViolation := func(attrNode *ast.Node, name string) {
			for _, block := range blockAncestors(attrNode) {
				if reportVariableViolation(attrNode, name, block.Pos()) {
					return
				}
			}
		}

		return rule.RuleListeners{
			ast.KindBlock: func(node *ast.Node) {
				initBlock(node.Pos())
			},

			ast.KindFunctionDeclaration: func(node *ast.Node) {
				ancestors := blockAncestors(node)
				if len(ancestors) == 0 {
					return
				}
				violation := getNodeViolationType(node)
				if violation == "" {
					return
				}
				nameNode := node.AsFunctionDeclaration().Name()
				if nameNode == nil || nameNode.Kind != ast.KindIdentifier {
					return
				}
				blockPos := ancestors[0].Pos()
				initBlock(blockPos)
				blockVariableNameSets[blockPos][violation][nameNode.AsIdentifier().Text] = true
			},

			ast.KindVariableDeclaration: func(node *ast.Node) {
				varDecl := node.AsVariableDeclaration()
				if varDecl.Initializer == nil {
					return
				}

				declList := node.Parent
				if declList == nil || declList.Kind != ast.KindVariableDeclarationList {
					return
				}
				if declList.Flags&ast.NodeFlagsConst == 0 {
					return
				}

				if declList.Parent == nil || declList.Parent.Kind != ast.KindVariableStatement {
					return
				}
				ancestors := blockAncestors(node)
				if len(ancestors) == 0 {
					return
				}
				violation := getNodeViolationType(varDecl.Initializer)
				if violation == "" {
					return
				}
				nameNode := varDecl.Name()
				if nameNode == nil || nameNode.Kind != ast.KindIdentifier {
					return
				}
				blockPos := ancestors[0].Pos()
				initBlock(blockPos)
				blockVariableNameSets[blockPos][violation][nameNode.AsIdentifier().Text] = true
			},

			ast.KindJsxAttribute: func(node *ast.Node) {
				attr := node.AsJsxAttribute()
				nameNode := attr.Name()
				if opts.ignoreRefs && nameNode != nil && nameNode.Kind == ast.KindIdentifier && nameNode.AsIdentifier().Text == "ref" {
					return
				}
				initializer := attr.Initializer
				if initializer == nil || initializer.Kind != ast.KindJsxExpression {
					return
				}
				expr := unwrap(initializer.AsJsxExpression().Expression)
				if expr == nil {
					return
				}
				if opts.ignoreDOMComponents && reactutil.IsDOMComponent(reactutil.GetJsxParentElement(node)) {
					return
				}
				if expr.Kind == ast.KindIdentifier {
					findVariableViolation(node, expr.AsIdentifier().Text)
					return
				}
				if violation := getNodeViolationType(expr); violation != "" {
					ctx.ReportNode(node, message(violation))
				}
			},
		}
	},
}

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

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