no_danger_with_children

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 NoDangerWithChildrenRule = rule.Rule{
	Name: "react/no-danger-with-children",
	Run: func(ctx rule.RuleContext, options any) rule.RuleListeners {

		resolveObjectLiteralInit := func(ident *ast.Node) *ast.ObjectLiteralExpression {
			if ident == nil || ident.Kind != ast.KindIdentifier {
				return nil
			}

			if ctx.TypeChecker == nil {
				return nil
			}
			decl := utils.GetDeclaration(ctx.TypeChecker, ident)
			if decl == nil || decl.Kind != ast.KindVariableDeclaration {
				return nil
			}
			init := decl.AsVariableDeclaration().Initializer
			if init == nil {
				return nil
			}
			init = ast.SkipParentheses(init)
			if init.Kind != ast.KindObjectLiteralExpression {
				return nil
			}
			return init.AsObjectLiteralExpression()
		}

		// findObjectPropByName reports whether the object literal has a
		// property with the given name — either directly (Identifier key, to
		// match upstream's `prop.key.name === propName`) or via a spread whose
		// initializer resolves to another object literal.
		//
		// `seen` tracks Identifier names already followed through a spread,
		// so self-referencing initializers like `const props = { ...props }`
		// terminate instead of looping.
		//
		// Upstream intentionally matches ONLY Identifier keys — a
		// StringLiteral key (`"children": "x"`) has `.value` but no `.name`,
		// so upstream's `prop.key.name === propName` is always false on it.
		// We keep parity by not using `utils.GetStaticPropertyName` here.
		var findObjectPropByName func(obj *ast.ObjectLiteralExpression, name string, seen map[string]bool) bool
		findObjectPropByName = func(obj *ast.ObjectLiteralExpression, name string, seen map[string]bool) bool {
			if obj == nil || obj.Properties == nil {
				return false
			}
			for _, prop := range obj.Properties.Nodes {
				switch prop.Kind {
				case ast.KindPropertyAssignment:
					keyNode := prop.AsPropertyAssignment().Name()
					if keyNode != nil && keyNode.Kind == ast.KindIdentifier &&
						keyNode.AsIdentifier().Text == name {
						return true
					}
				case ast.KindShorthandPropertyAssignment:
					keyNode := prop.AsShorthandPropertyAssignment().Name()
					if keyNode != nil && keyNode.Kind == ast.KindIdentifier &&
						keyNode.AsIdentifier().Text == name {
						return true
					}
				case ast.KindSpreadAssignment:
					expr := ast.SkipParentheses(prop.AsSpreadAssignment().Expression)
					if expr.Kind != ast.KindIdentifier {
						continue
					}
					spreadName := expr.AsIdentifier().Text
					if seen[spreadName] {
						continue
					}
					inner := resolveObjectLiteralInit(expr)
					if inner == nil {
						continue
					}
					nextSeen := make(map[string]bool, len(seen)+1)
					for k, v := range seen {
						nextSeen[k] = v
					}
					nextSeen[spreadName] = true
					if findObjectPropByName(inner, name, nextSeen) {
						return true
					}
				}
			}
			return false
		}

		asPropsObject := func(node *ast.Node) (*ast.ObjectLiteralExpression, map[string]bool) {
			node = ast.SkipParentheses(node)
			if node.Kind == ast.KindObjectLiteralExpression {
				return node.AsObjectLiteralExpression(), map[string]bool{}
			}
			if node.Kind == ast.KindIdentifier {
				if obj := resolveObjectLiteralInit(node); obj != nil {
					return obj, map[string]bool{node.AsIdentifier().Text: true}
				}
			}
			return nil, nil
		}

		findJsxAttr := func(element *ast.Node, name string) bool {
			for _, attr := range reactutil.GetJsxElementAttributes(element) {
				switch attr.Kind {
				case ast.KindJsxAttribute:
					nameNode := attr.AsJsxAttribute().Name()
					if nameNode != nil && nameNode.Kind == ast.KindIdentifier &&
						nameNode.AsIdentifier().Text == name {
						return true
					}
				case ast.KindJsxSpreadAttribute:
					expr := ast.SkipParentheses(attr.AsJsxSpreadAttribute().Expression)
					if expr.Kind != ast.KindIdentifier {
						continue
					}
					inner := resolveObjectLiteralInit(expr)
					if inner == nil {
						continue
					}
					seen := map[string]bool{expr.AsIdentifier().Text: true}
					if findObjectPropByName(inner, name, seen) {
						return true
					}
				}
			}
			return false
		}

		isLineBreak := func(child *ast.Node) bool {
			if child == nil || child.Kind != ast.KindJsxText {
				return false
			}
			text := child.AsJsxText().Text
			if strings.TrimSpace(text) != "" {
				return false
			}
			return strings.Contains(text, "\n")
		}

		checkJsx := func(elementForAttrs, reportNode *ast.Node, firstChild *ast.Node) {
			hasChildren := false
			if firstChild != nil && !isLineBreak(firstChild) {
				hasChildren = true
			} else if findJsxAttr(elementForAttrs, "children") {
				hasChildren = true
			}
			if !hasChildren {
				return
			}
			if findJsxAttr(elementForAttrs, "dangerouslySetInnerHTML") {
				ctx.ReportNode(reportNode, rule.RuleMessage{
					Id:          "dangerWithChildren",
					Description: dangerWithChildrenMessage,
				})
			}
		}

		return rule.RuleListeners{
			ast.KindJsxElement: func(node *ast.Node) {
				jsx := node.AsJsxElement()
				var firstChild *ast.Node
				if jsx.Children != nil && len(jsx.Children.Nodes) > 0 {
					firstChild = jsx.Children.Nodes[0]
				}
				checkJsx(jsx.OpeningElement, node, firstChild)
			},
			ast.KindJsxSelfClosingElement: func(node *ast.Node) {
				checkJsx(node, node, nil)
			},
			ast.KindCallExpression: func(node *ast.Node) {
				call := node.AsCallExpression()
				if !isCreateElementCallee(call.Expression) {
					return
				}
				if call.Arguments == nil || len(call.Arguments.Nodes) < 2 {
					return
				}
				obj, seen := asPropsObject(call.Arguments.Nodes[1])
				if obj == nil {
					return
				}
				if !findObjectPropByName(obj, "dangerouslySetInnerHTML", seen) {
					return
				}
				hasChildren := len(call.Arguments.Nodes) > 2
				if !hasChildren {
					hasChildren = findObjectPropByName(obj, "children", seen)
				}
				if hasChildren {
					ctx.ReportNode(node, rule.RuleMessage{
						Id:          "dangerWithChildren",
						Description: dangerWithChildrenMessage,
					})
				}
			},
		}
	},
}

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