no_unsafe_optional_chaining

package
v0.5.2 Latest Latest
Warning

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

Go to latest
Published: May 7, 2026 License: MIT Imports: 3 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var NoUnsafeOptionalChainingRule = rule.Rule{
	Name: "no-unsafe-optional-chaining",
	Run: func(ctx rule.RuleContext, options any) rule.RuleListeners {
		opts := parseOptions(options)

		unsafeOptionalChainMsg := rule.RuleMessage{
			Id:          "unsafeOptionalChain",
			Description: "Unsafe usage of optional chaining. If it short-circuits with 'undefined' the evaluation will throw TypeError.",
		}

		unsafeArithmeticMsg := rule.RuleMessage{
			Id:          "unsafeArithmetic",
			Description: "Unsafe arithmetic operation on optional chaining. It can result in NaN.",
		}

		checkUnsafeUsage := func(expr *ast.Node) {
			checkUndefinedShortCircuit(expr, func(chainNode *ast.Node) {
				ctx.ReportNode(chainNode, unsafeOptionalChainMsg)
			})
		}

		checkUnsafeArithmetic := func(expr *ast.Node) {
			checkUndefinedShortCircuit(expr, func(chainNode *ast.Node) {
				ctx.ReportNode(chainNode, unsafeArithmeticMsg)
			})
		}

		listeners := rule.RuleListeners{}

		listeners[ast.KindCallExpression] = func(node *ast.Node) {
			if ast.IsOptionalChain(node) {
				return
			}
			checkUnsafeUsage(node.AsCallExpression().Expression)
		}

		listeners[ast.KindNewExpression] = func(node *ast.Node) {
			checkUnsafeUsage(node.AsNewExpression().Expression)
		}

		listeners[ast.KindTaggedTemplateExpression] = func(node *ast.Node) {
			checkUnsafeUsage(node.AsTaggedTemplateExpression().Tag)
		}

		listeners[ast.KindPropertyAccessExpression] = func(node *ast.Node) {
			if ast.IsOptionalChain(node) {
				return
			}
			checkUnsafeUsage(node.AsPropertyAccessExpression().Expression)
		}

		listeners[ast.KindElementAccessExpression] = func(node *ast.Node) {
			if ast.IsOptionalChain(node) {
				return
			}
			checkUnsafeUsage(node.AsElementAccessExpression().Expression)
		}

		listeners[ast.KindBinaryExpression] = func(node *ast.Node) {
			bin := node.AsBinaryExpression()
			if bin == nil || bin.OperatorToken == nil {
				return
			}

			if ast.IsDestructuringAssignment(node) {
				checkUnsafeUsage(bin.Right)
				return
			}

			op := bin.OperatorToken.Kind

			switch op {
			case ast.KindInKeyword, ast.KindInstanceOfKeyword:
				checkUnsafeUsage(bin.Right)

			case ast.KindPlusToken, ast.KindMinusToken, ast.KindAsteriskToken,
				ast.KindSlashToken, ast.KindPercentToken, ast.KindAsteriskAsteriskToken:
				if opts.disallowArithmeticOperators {
					checkUnsafeArithmetic(bin.Left)
					checkUnsafeArithmetic(bin.Right)
				}

			case ast.KindPlusEqualsToken, ast.KindMinusEqualsToken,
				ast.KindAsteriskEqualsToken, ast.KindAsteriskAsteriskEqualsToken,
				ast.KindSlashEqualsToken, ast.KindPercentEqualsToken:
				if opts.disallowArithmeticOperators {
					checkUnsafeArithmetic(bin.Right)
				}
			}
		}

		if opts.disallowArithmeticOperators {
			listeners[ast.KindPrefixUnaryExpression] = func(node *ast.Node) {
				pue := node.AsPrefixUnaryExpression()
				if pue.Operator == ast.KindPlusToken || pue.Operator == ast.KindMinusToken {
					checkUnsafeArithmetic(pue.Operand)
				}
			}
		}

		listeners[ast.KindSpreadElement] = func(node *ast.Node) {
			if node.Parent != nil && node.Parent.Kind == ast.KindObjectLiteralExpression {
				return
			}
			checkUnsafeUsage(node.AsSpreadElement().Expression)
		}

		listeners[ast.KindForOfStatement] = func(node *ast.Node) {
			checkUnsafeUsage(node.AsForInOrOfStatement().Expression)
		}

		listeners[ast.KindVariableDeclaration] = func(node *ast.Node) {
			vd := node.AsVariableDeclaration()
			if name := vd.Name(); name != nil && ast.IsBindingPattern(name) {
				checkUnsafeUsage(vd.Initializer)
			}
		}

		listeners[ast.KindBindingElement] = func(node *ast.Node) {
			be := node.AsBindingElement()
			if name := be.Name(); name != nil && ast.IsBindingPattern(name) {
				checkUnsafeUsage(be.Initializer)
			}
		}

		listeners[ast.KindWithStatement] = func(node *ast.Node) {
			checkUnsafeUsage(node.AsWithStatement().Expression)
		}

		classHandler := func(node *ast.Node) {
			extendsElement := ast.GetClassExtendsHeritageElement(node)
			if extendsElement == nil {
				return
			}
			exprWithType := extendsElement.AsExpressionWithTypeArguments()
			if exprWithType == nil {
				return
			}
			checkUnsafeUsage(exprWithType.Expression)
		}
		listeners[ast.KindClassDeclaration] = classHandler
		listeners[ast.KindClassExpression] = classHandler

		return listeners
	},
}

https://eslint.org/docs/latest/rules/no-unsafe-optional-chaining

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