jsx_indent_props

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: 4 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var JsxIndentPropsRule = rule.Rule{
	Name: "react/jsx-indent-props",
	Run: func(ctx rule.RuleContext, options any) rule.RuleListeners {
		indentType, indentSize, indentChar, indentIsFirst, ignoreTernaryOperator := parseOptions(options)

		text := ctx.SourceFile.Text()
		lineMap := ctx.SourceFile.ECMALineMap()

		firstNonWhitespaceCharOnLine := func(pos int) byte {
			start := reactutil.IndentLineStart(lineMap, pos)
			for i := start; i < len(text); i++ {
				c := text[i]
				if c == ' ' || c == '\t' {
					continue
				}
				if c == '\n' || c == '\r' {
					return 0
				}
				return c
			}
			return 0
		}

		firstLineContainsBracket := func(node *ast.Node) bool {
			trimmed := utils.TrimNodeTextRange(ctx.SourceFile, node)
			lineStart := reactutil.IndentLineStart(lineMap, trimmed.Pos())
			end := trimmed.End()
			for i := lineStart; i < end && i < len(text); i++ {
				c := text[i]
				if c == '\n' {
					break
				}
				if c == '<' {
					return true
				}
			}
			return false
		}

		check := func(node *ast.Node) {
			var props []*ast.Node
			switch node.Kind {
			case ast.KindJsxOpeningElement:
				opening := node.AsJsxOpeningElement()
				if opening.Attributes != nil {
					attrs := opening.Attributes.AsJsxAttributes()
					if attrs != nil && attrs.Properties != nil {
						props = attrs.Properties.Nodes
					}
				}
			case ast.KindJsxSelfClosingElement:
				self := node.AsJsxSelfClosingElement()
				if self.Attributes != nil {
					attrs := self.Attributes.AsJsxAttributes()
					if attrs != nil && attrs.Properties != nil {
						props = attrs.Properties.Nodes
					}
				}
			}
			if len(props) == 0 {
				return
			}

			openingTrimmed := utils.TrimNodeTextRange(ctx.SourceFile, node)
			openingStart := openingTrimmed.Pos()

			leadChar := firstNonWhitespaceCharOnLine(openingStart)
			isUsingOperator := leadChar == '?' || leadChar == ':'

			elementIndent := reactutil.IndentLeading(text, lineMap, openingStart, indentChar)

			var propIndent int
			if indentIsFirst {

				propIndent = reactutil.NodeStartUTF16Column(ctx.SourceFile, props[0])
			} else {
				propIndent = elementIndent + indentSize
			}

			nestedIndent := propIndent
			bumpApplied := false

			for _, prop := range props {

				if firstLineContainsBracket(prop) {
					isUsingOperator = false
				}

				if !reactutil.IsNodeFirstInLine(ctx.SourceFile, prop) {
					continue
				}

				if !bumpApplied && isUsingOperator && !indentIsFirst && !ignoreTernaryOperator {
					nestedIndent += indentSize
					bumpApplied = true
					isUsingOperator = false
				}

				actualIndent := reactutil.NodeStartIndent(ctx.SourceFile, prop, indentChar)
				if actualIndent != nestedIndent {
					reactutil.ReportIndentReplaceLeading(ctx, prop, nestedIndent, actualIndent, indentChar, indentType)
				}
			}
		}

		return rule.RuleListeners{
			ast.KindJsxOpeningElement:     check,
			ast.KindJsxSelfClosingElement: check,
		}
	},
}

JsxIndentPropsRule enforces JSX prop indentation.

Ported from eslint-plugin-react's `jsx-indent-props` rule. The rule walks every JsxOpeningElement / JsxSelfClosingElement, computes the expected prop indent (either `<element-indent> + indentSize` for the numeric / tab modes, or the column of the first prop for `'first'`), and reports each attribute whose leading-whitespace count differs.

tsgo↔ESTree shape adjustments (vs the upstream JS rule):

  • Self-closing `<Foo />` is `JsxSelfClosingElement` with no wrapping `JsxElement`, so both `JsxOpeningElement` and `JsxSelfClosingElement` share the same listener.
  • Source-line scans (line-start, leading whitespace, first non-WS char) run against `SourceFile.Text()`; line numbers come from the ECMA line map via `scanner.ComputeLineOfPosition`.

Ternary operator handling: upstream maintains a `line.isUsingOperator` flag that is set when the line containing the JSX `<` starts with `?` or `:` after whitespace. When that flag is on (and `'first'` mode is off and `ignoreTernaryOperator` is off), the FIRST prop that sits first-in-line receives an extra `indentSize` bump, after which the flag is cleared. We replicate that behaviour with a per-element `bumpApplied` boolean and a per-prop bracket reset (mirrors upstream's `useBracket` reset inside `getNodeIndent` — any prop whose first source line contains `<` cancels the pending bump, exactly the same way upstream's per-call side effect would).

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