reactutil

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

Documentation

Index

Constants

View Source
const DefaultReactCreateClass = "createReactClass"

DefaultReactCreateClass is the fallback ES5 factory name when `settings.react.createClass` is not configured, matching eslint-plugin-react.

View Source
const DefaultReactFragment = "Fragment"

DefaultReactFragment is the fallback fragment name for JSX shorthand fragment diagnostics when `settings.react.fragment` is not configured, matching eslint-plugin-react.

View Source
const DefaultReactPragma = "React"

DefaultReactPragma is the fallback object name for createElement calls when `settings.react.pragma` is not configured, matching eslint-plugin-react.

Variables

This section is empty.

Functions

func ApplyData added in v0.5.3

func ApplyData(template string, data map[string]string) string

ApplyData expands `{{key}}` placeholders in a message template using the given data map, mirroring ESLint's `RuleMessage.data` interpolation. Keys not present in `data` are left untouched, matching ESLint's behavior of passing through unknown placeholders verbatim. Use this whenever a rule emits a templated `RuleMessage.Description` so the in-rule code reads like the upstream `messages` table instead of hand-rolled `strings.ReplaceAll` loops.

func BindingIdentifierName added in v0.5.2

func BindingIdentifierName(n *ast.Node) string

BindingIdentifierName returns the identifier text of a named declaration's binding, or "" when the declaration is anonymous, the binding is a pattern rather than a bare Identifier, or `n` is nil.

func CheckUnsafeAtReactVersion added in v0.5.2

func CheckUnsafeAtReactVersion(major, minor, patch int) func(map[string]interface{}) bool

CheckUnsafeAtReactVersion returns a [NoMethodSetStateConfig.ShouldCheckUnsafe] callback equivalent to upstream's `testReactVersion(context, '>= X.Y.Z')`: true iff the configured (or defaulted) React version is at least major.minor.patch.

func ClassHasMethodNamed added in v0.5.3

func ClassHasMethodNamed(classNode *ast.Node, methodName string) bool

ClassHasMethodNamed reports whether `classNode` has a method (regular MethodDeclaration, GetAccessor, SetAccessor, or Constructor) whose key resolves via IdentifierOrPrivateName to `methodName`. PropertyDeclaration (class-field assignment like `name = () => {}`) does NOT count — upstream's MethodDefinition listeners fire on real methods only, not class fields.

Mirrors upstream `astUtil.getComponentProperties(node).some(p => getPropertyName(p) === '<methodName>')` for the subset of properties that have method semantics.

func ClassKeywordStart added in v0.5.3

func ClassKeywordStart(text string, node *ast.Node) int

ClassKeywordStart returns the report-anchor start position for a ClassDeclaration / ClassExpression aligned with ESLint's `node.loc.start` for that class.

ESTree wraps `export class …` and `export default class …` in `ExportNamedDeclaration` / `ExportDefaultDeclaration` and exposes the inner `ClassDeclaration` starting at the `class` keyword. tsgo flattens these — `export` / `default` end up as Modifier kinds on the class node itself, shifting `node.Pos()` to the `export` token. We trim those two modifier kinds back out to recover the upstream-aligned start.

Decorators (`@dec`), TS `abstract` / `declare` / accessibility modifiers are PART of the class's range upstream — TSESTree keeps them on the ClassDeclaration. We stop trimming the moment a non-export/default modifier appears so the report range still spans those.

Pass `sourceFile.Text()` as `text` so trailing trivia after the modifier list is properly skipped.

func EnclosingClass added in v0.5.2

func EnclosingClass(node *ast.Node) *ast.Node

EnclosingClass returns the nearest ClassDeclaration / ClassExpression ancestor of `node`, or nil when `node` is at the top level. Used by rules that need to test whether a class member belongs to a React component.

func EntityNameRightmost added in v0.5.2

func EntityNameRightmost(name *ast.Node) *ast.Node

EntityNameRightmost returns the rightmost Identifier of a TypeReference's EntityName. For a bare `Foo`, returns `Foo`. For `A.B.C`, returns `C`. Returns nil if no identifier can be extracted.

func EsTreeName added in v0.5.2

func EsTreeName(nameNode *ast.Node) string

EsTreeName returns the string an ESTree consumer would read from `node.name` for an Identifier / PrivateIdentifier. PrivateIdentifier strips the leading `#` per spec (tsgo retains it, so we trim). Any other node kind — ComputedPropertyName, StringLiteral, NumericLiteral, etc. — has no `.name` in ESTree and yields "". Callers that compare against a known identifier string therefore get the correct "never equal" answer without extra guards.

Used in both contexts the rule cares about: the member-expression property (`callee.property.name`) and the container key (`ancestor.key.name`). Neither is a true "static property name" in the wider sense — e.g. `this['setState']()` must NOT match (upstream: `'name' in callee.property` is false), so reusing `utils.GetStaticPropertyName` here would be incorrect (it resolves string literals as static names).

func ExtendsReactComponent added in v0.5.0

func ExtendsReactComponent(classNode *ast.Node, pragma string) bool

ExtendsReactComponent reports whether `classNode` (a ClassDeclaration or ClassExpression) has an `extends` clause referencing `Component` or `PureComponent` — either as a bare identifier or qualified by the configured pragma (e.g. `React.Component`). Parentheses are skipped. Pass the empty string for pragma to default to `DefaultReactPragma`.

NOTE: Matches the name regex used by eslint-plugin-react's `componentUtil.isES6Component` (`/^(Pure)?Component$/`). Aliased imports (e.g. `import { Component as C }`) are not resolved — same as the upstream rule.

func ExtendsReactPureComponent added in v0.5.1

func ExtendsReactPureComponent(classNode *ast.Node, pragma string) bool

ExtendsReactPureComponent reports whether `classNode` (a ClassDeclaration or ClassExpression) has an `extends` clause referencing `PureComponent` — either as a bare identifier or qualified by the configured pragma (e.g. `React.PureComponent`). Parentheses are skipped. Pass the empty string for pragma to default to `DefaultReactPragma`.

Mirrors eslint-plugin-react's `componentUtil.isPureComponent`, which uses the regex `/^(<pragma>\.)?PureComponent$/` over the rendered extends-clause text. Plain `Component` does NOT match (use ExtendsReactComponent for the broader detection).

func FirstParamType added in v0.5.2

func FirstParamType(fn *ast.Node) *ast.Node

FirstParamType returns the type annotation of the first parameter of `fn` (a FunctionDeclaration / FunctionExpression / ArrowFunction), or nil when the function has no parameters or the first parameter is untyped.

func FunctionBody added in v0.5.3

func FunctionBody(fn *ast.Node) *ast.Node

FunctionBody returns the body of a function-like node, mirroring `FunctionParameters`'s coverage. Returns nil when the kind is not function-like, or when the body is absent (overload signatures, abstract methods, ambient declarations).

Arrow expression bodies (`() => expr`) are returned as the expression node itself — callers that distinguish block bodies from expression bodies should branch on `body.Kind == ast.KindBlock`.

func FunctionParameters added in v0.5.2

func FunctionParameters(fn *ast.Node) []*ast.Node

FunctionParameters returns the parameter list of a function-like node (FunctionDeclaration / FunctionExpression / ArrowFunction). Returns nil for nil input or any other node kind. Methods / accessors / constructors are intentionally not covered — callers that need them should add the kind explicitly to keep this helper a thin shim over the common shapes.

func FunctionReturnsJSX added in v0.5.1

func FunctionReturnsJSX(fn *ast.Node, pragma string) bool

FunctionReturnsJSX is the strict sibling of FunctionReturnsJSXOrNull: a `null` return does NOT qualify on its own. `<pragma>.createElement(...)` calls still qualify. Mirrors upstream jsxUtil.isReturningJSX invoked with `strict=true, ignoreNull=true`. `<pragma>.createElement(...)` calls still qualify. Pass an empty pragma to default to "React".

func FunctionReturnsJSXOrNull added in v0.5.1

func FunctionReturnsJSXOrNull(fn *ast.Node, pragma string) bool

FunctionReturnsJSXOrNull reports whether the function's body contains a `return <jsx/>` / `return null` / `return <pragma>.createElement(...)` at depth ≤ 1 (nested functions excluded), OR — for an arrow with expression body — whether that expression qualifies under the same rules. ConditionalExpression is traversed so `return cond ? <jsx/> : null` qualifies.

Identifier returns (`return view` where `view` is bound to a JSX value) are resolved structurally via a local block scan. Use `FunctionReturnsJSXOrNullWithChecker` for full TypeChecker-based scope resolution.

Mirrors upstream jsxUtil.isReturningJSX invoked with default arguments (which accept JSX, `null`, and `<pragma>.createElement(...)` returns). Pass an empty pragma to default to "React".

func FunctionReturnsJSXOrNullWithChecker added in v0.5.1

func FunctionReturnsJSXOrNullWithChecker(fn *ast.Node, pragma string, tc *checker.Checker) bool

FunctionReturnsJSXOrNullWithChecker is the TypeChecker-aware variant of FunctionReturnsJSXOrNull. When `tc` is non-nil, Identifier returns are resolved through `GetSymbolAtLocation` → `Declarations[0]` → `VariableDeclaration.Initializer`, matching upstream's `findVariableByName` scope walk semantically (any binding the TS resolver can reach is considered, not just bindings in the immediately-enclosing block). When `tc` is nil, falls back to the local-block scan.

func FunctionReturnsJSXWithChecker added in v0.5.1

func FunctionReturnsJSXWithChecker(fn *ast.Node, pragma string, tc *checker.Checker) bool

FunctionReturnsJSXWithChecker is the TypeChecker-aware strict variant. See FunctionReturnsJSXOrNullWithChecker for the resolution semantics.

func GetEnclosingReactComponent added in v0.5.0

func GetEnclosingReactComponent(node *ast.Node, pragma, createClass string) *ast.Node

GetEnclosingReactComponent is IsInsideReactComponent's sibling that returns the component node itself (the ClassDeclaration / ClassExpression, or the ObjectLiteralExpression passed to createReactClass) rather than a bool. Returns nil when `node` is not inside a React component. See IsInsideReactComponent for the detection rules.

func GetEnclosingReactComponentOrStateless added in v0.5.0

func GetEnclosingReactComponentOrStateless(node *ast.Node, pragma, createClass string, wrappers []ComponentWrapperEntry) *ast.Node

GetEnclosingReactComponentOrStateless is GetEnclosingReactComponent extended with eslint-plugin-react's `getParentStatelessComponent` fallback: when no enclosing ES6 class / ES5 createReactClass component is found, the nearest FunctionLike ancestor that looks like a functional component (capital-cased name + returns JSX/null) is returned.

Priority matches upstream's `getParentComponent`:

getParentES6Component || getParentES5Component || getParentStatelessComponent

so when a mutation node is inside an inner function nested within an outer class component, the OUTER class component is returned (preventing the inner stateless candidate from masking the class boundary).

Only a restricted subset of upstream's heuristics is implemented — the patterns covering production React code: named FunctionDeclaration, FunctionExpression / ArrowFunction assigned to a capital-cased VariableDeclarator, PropertyAssignment, or ExportAssignment (default export), plus function expression in a CallExpression (e.g. React.memo wrapper — approximate match). This is intentionally conservative: missed detection causes a rule miss, over-detection would cause false-positive reports in non-component functions.

func GetJsxChildren added in v0.5.2

func GetJsxChildren(parent *ast.Node) []*ast.Node

GetJsxChildren returns the child-node list of a JsxElement or JsxFragment, or nil for other kinds (JsxSelfClosingElement has no children) and when the container's child list is absent.

func GetJsxElementAttributes added in v0.5.0

func GetJsxElementAttributes(element *ast.Node) []*ast.Node

GetJsxElementAttributes returns the attribute nodes of a JsxOpeningElement or JsxSelfClosingElement, or nil for other kinds or when the element has no attributes. Each returned node is either a JsxAttribute or a JsxSpreadAttribute.

func GetJsxElementTypeString added in v0.5.0

func GetJsxElementTypeString(node *ast.Node) string

GetJsxElementTypeString returns the jsx-ast-utils `elementType(node)` equivalent — the dotted / namespaced display string of a JSX tag name as an ESTree-compatible source caller would see it. `node` may be either a JsxOpeningElement / JsxSelfClosingElement, or a raw tag-name node. Returns "" for shapes that don't correspond to a legal React/JSX element type (e.g. a computed member access), so callers can treat "" as "not a user component".

Supported tag shapes:

  • `<Foo>` / `<foo>` → "Foo" / "foo"
  • `<Foo.Bar.Baz>` → "Foo.Bar.Baz" (PropertyAccessExpression chain)
  • `<this.Foo>` → "this.Foo" (ThisKeyword base)
  • `<ns:Name>` → "ns:Name" (JsxNamespacedName)

This is AST-driven — interior whitespace or comments in unusual forms (e.g. `<Foo . Bar />`) are normalized away, matching jsx-ast-utils.

func GetJsxParentElement added in v0.5.0

func GetJsxParentElement(attr *ast.Node) *ast.Node

GetJsxParentElement returns the JsxOpeningElement or JsxSelfClosingElement that owns the given JsxAttribute (or JsxSpreadAttribute), or nil if not applicable.

func GetJsxPropName

func GetJsxPropName(node *ast.Node) string

GetJsxPropName returns the display name of a JSX node. For JsxAttribute: returns the attribute name (including namespaced names like "foo:bar"). For JsxSpreadAttribute: returns "spread". For Identifier nodes (e.g. tag names): returns the identifier text. For unknown nodes: returns "".

func GetJsxTagBaseIdentifier added in v0.5.0

func GetJsxTagBaseIdentifier(tagName *ast.Node) *ast.Node

GetJsxTagBaseIdentifier returns the leftmost Identifier of a JSX tag-name node — i.e. the symbol a rule must resolve to classify the tag. Pass the tag-name node obtained from `GetJsxTagName` (or directly from `JsxOpeningElement.TagName` / `JsxSelfClosingElement.TagName`). Returns nil when the tag does not terminate in an Identifier (ThisKeyword base, JsxNamespacedName, unknown shape).

Shapes handled:

  • `<Foo />` → Identifier("Foo")
  • `<Foo.Bar />` → Identifier("Foo")
  • `<Foo.Bar.Baz />` → Identifier("Foo")
  • `<this />` / `<this.X />` → nil (ThisKeyword base)
  • `<a:b />` → nil (JsxNamespacedName — not an identifier reference in any scope)
  • `<foo-bar />` → Identifier("foo-bar") (tsgo preserves the hyphenated text verbatim; callers decide whether that's DOM).

func GetJsxTagName added in v0.5.0

func GetJsxTagName(element *ast.Node) *ast.Node

GetJsxTagName returns the tag-name node of a JsxOpeningElement or JsxSelfClosingElement, or nil for other kinds.

func GetParentReactComponentScopeBased added in v0.5.2

func GetParentReactComponentScopeBased(node *ast.Node, pragma, createClass string) *ast.Node

GetParentReactComponentScopeBased mirrors upstream's `componentUtil.getParentES6Component(context, node) || componentUtil.getParentES5Component(context, node)` exactly — the helper used directly by `no-string-refs` and `no-access-state-in-setstate`.

**NOT equivalent to `GetEnclosingReactComponent`**: that one mimics `Components.set`'s free AST ancestor walk; this one applies the stricter scope-based rules:

  • **ES6 path**: finds the FIRST enclosing class (innermost). If it extends `Component` / `PureComponent` (bare or pragma-qualified), returns it; otherwise stops searching outer classes (mirrors upstream's `while scope.type !== 'class'` loop).

  • **ES5 path**: walks each enclosing FunctionLike scope. For each, checks whether its parent.parent reaches a `createReactClass(...)` argument ObjectLiteralExpression. This crosses non-React classes freely — only function-like scopes are inspected.

Empirically verified equivalent to ESLint output. Pass empty strings for pragma/createClass to fall back to defaults.

func GetParentReactComponentScopeBasedOrStateless added in v0.5.2

func GetParentReactComponentScopeBasedOrStateless(node *ast.Node, pragma, createClass string, wrappers []ComponentWrapperEntry) *ast.Node

GetParentReactComponentScopeBasedOrStateless mirrors upstream's `utils.getParentComponent(node)` = `getParentES6Component || getParentES5Component || getParentStatelessComponent`.

**NOT equivalent to `GetEnclosingReactComponentOrStateless`**: that one uses `Components.set`'s free AST ancestor walk. This helper applies the stricter scope-based ES6+ES5 detection (see `GetParentReactComponentScopeBased`) and falls back to stateless component detection. Use this for rules that call `utils.getParentComponent(node)` directly inside a listener and gate their report on the result being non-null — e.g. `no-direct-mutation-state`'s `shouldIgnoreComponent(component)` check, which bails when the result is undefined.

Pass empty strings for pragma/createClass to fall back to defaults.

func GetParentStatelessComponent added in v0.5.3

func GetParentStatelessComponent(node *ast.Node, pragma string, wrappers []ComponentWrapperEntry) *ast.Node

GetParentStatelessComponent mirrors eslint-plugin-react's `utils.getParentStatelessComponent(node)`: walk up enclosing FunctionLike scopes from `node` and return the first one classified as a stateless functional component. A non-component function does NOT stop the walk — the next outer FunctionLike still gets a chance, matching upstream's `scope.upper` traversal.

ES6 class scopes / class field initializers / module scope are non-FunctionLike nodes that are simply skipped during the walk.

Pass empty `pragma` to default to `DefaultReactPragma`. `wrappers` should be the resolved `settings.componentWrapperFunctions` list (plus the built-in `memo` / `forwardRef` defaults) so user-configured HOCs are recognized as component-wrapping calls.

func GetReactCreateClass added in v0.5.0

func GetReactCreateClass(settings map[string]interface{}) string

GetReactCreateClass reads `settings.react.createClass` from the config settings map. Returns DefaultReactCreateClass when the setting is absent, not a string, or empty.

func GetReactFragmentPragma added in v0.5.0

func GetReactFragmentPragma(settings map[string]interface{}) string

GetReactFragmentPragma reads `settings.react.fragment` from the config settings map. Returns DefaultReactFragment when the setting is absent, not a string, or empty.

func GetReactPragma added in v0.5.0

func GetReactPragma(settings map[string]interface{}) string

GetReactPragma reads `settings.react.pragma` from the config settings map. Returns DefaultReactPragma when the setting is absent, not a string, or empty.

func GlobToRegex added in v0.5.1

func GlobToRegex(pattern string) *regexp.Regexp

GlobToRegex converts a minimatch-style glob into a fully anchored regular expression. Supports the subset of minimatch syntax the eslint-plugin-react ecosystem relies on:

  • `*` — any run of characters (`**` collapses to `*`)
  • `?` — a single character
  • `[abc]` — character class
  • `[!abc]` / `[^abc]` — negated character class
  • `{a,b,c}` — brace expansion (nestable)
  • `?(a|b)` — zero or one of alternatives (extglob)
  • `*(a|b)` — zero or more of alternatives (extglob)
  • `+(a|b)` — one or more of alternatives (extglob)
  • `@(a|b)` — exactly one of alternatives (extglob)
  • `!(a|b)` — extglob negation (RE2 lacks lookarounds; approximated as "zero or one" — exact-match semantics not supported)
  • `\X` — literal X

Leading `!` (whole-pattern negation) is intentionally NOT handled here: it inverts the whole-pattern match result and so cannot be expressed in a single anchored regex. Callers that need it should use `MatchGlob`, which special-cases the `!` prefix.

Compilation is cached per-pattern; the returned `*regexp.Regexp` is safe to share across goroutines. Returns nil only on malformed `[...]` classes that would produce a regex RE2 rejects (callers treat nil as "exact-match-only fallback"); upstream minimatch never throws here, so nil should not arise for any real-world glob.

func HorizontalWhitespacePrefix added in v0.5.3

func HorizontalWhitespacePrefix(s string) string

HorizontalWhitespacePrefix returns the longest prefix of s consisting of ECMA WhiteSpace characters (excluding LineTerminators). It matches the behavior of `/^\s*/` applied to a single line — used by JSX layout rules that compute "indent of line N" without crossing into the next line.

LineTerminators (\n, \r, 
, 
) are NOT consumed, so passing a multi-line string only ever returns the indent of the first line.

func IdentifierOrPrivateName added in v0.5.3

func IdentifierOrPrivateName(name *ast.Node) string

IdentifierOrPrivateName mirrors ESLint's `node.name` lookup over a key / member-name node: returns the Identifier text directly, or the PrivateIdentifier text with the leading `#` stripped (per ESTree spec `PrivateIdentifier.name` excludes the `#`). Returns "" for any other Kind (StringLiteral, NumericLiteral, ComputedPropertyName, …) — those never populate `.name` upstream and never match upstream's `key.name === 'X'` gate.

Use this when a rule's upstream form is `X.name === 'Y'`. tsgo's PrivateIdentifier.Text retains the `#`, so a naive `.Text` compare would require the caller to know which input is private — this helper hides that.

func IndentLeading added in v0.5.3

func IndentLeading(text string, lineMap []core.TextPos, pos int, indentChar byte) int

IndentLeading counts consecutive `indentChar` bytes at the start of the line containing pos. Mirrors upstream ESLint's `getText(node, node.loc.start.column).match(/^[ ]+|^[\t]+/)` slice that every eslint-plugin-react indent-style rule uses to read a line's leading indent.

func IndentLineStart added in v0.5.3

func IndentLineStart(lineMap []core.TextPos, pos int) int

IndentLineStart returns the byte offset of the first character on the line containing pos, derived from the source file's ECMA line map.

func IsCasedLowercaseFirstLetter added in v0.5.2

func IsCasedLowercaseFirstLetter(s string) bool

IsCasedLowercaseFirstLetter mirrors upstream's `s[0] !== s[0].toUpperCase()` test (used by `forbid-component-props`'s componentName check and `forbid-dom-props`'s tag check): returns true iff the first rune is a cased letter currently in its lowercase form. Digits, `_`, `$`, and uppercase letters all return false. Distinct from IsLowercaseFirstLetter, which uses the looser `r === r.toLowerCase()` predicate (so `_Foo` returns true there, false here).

func IsCreateClassCall added in v0.5.0

func IsCreateClassCall(call *ast.CallExpression, pragma, createClass string) bool

IsCreateClassCall reports whether the given CallExpression's callee is `<createClass>(...)` or `<pragma>.<createClass>(...)`. Parentheses are skipped on both the callee and the pragma identifier. Pass the empty string for pragma/createClass to fall back to `DefaultReactPragma` / `DefaultReactCreateClass`.

func IsCreateElementCall

func IsCreateElementCall(callee *ast.Node, pragma string) bool

IsCreateElementCall reports whether the callee is `<pragma>.createElement` (or, with the WithChecker variant below, bare `createElement` resolved to a pragma-destructured binding).

Pass an empty pragma to default to "React"; pass GetReactPragma(ctx.Settings) to honor the user's `settings.react.pragma` configuration.

Parentheses AND TS expression wrappers (`as` / `satisfies` / `<T>x` / `x!`) are transparently skipped on both the callee itself and the pragma identifier (e.g. `(React).createElement` / `(React as any).createElement`). Optional-chain calls (`React?.createElement(...)`) are NOT recognized (upstream's `node.callee.object.name` access fails on the OptionalCall shape).

This non-checker variant only recognizes the member-access form. To recognize bare `createElement(...)` calls (with the `isDestructuredFromPragmaImport` gate), use `IsCreateElementCallWithChecker`.

func IsCreateElementCallWithChecker added in v0.5.1

func IsCreateElementCallWithChecker(callee *ast.Node, pragma string, tc *checker.Checker) bool

IsCreateElementCallWithChecker is the import-aware variant. When `tc` is non-nil, additionally recognizes bare `createElement(arg)` calls where the bare callee resolves to a pragma-destructured binding (`import { createElement } from 'react'` / `const { createElement } = React` / `const createElement = React.createElement` / `const { createElement } = require('react')`). Mirrors upstream `isCreateElement`'s second branch byte-for-byte.

func IsCreateOrCloneElementCall added in v0.5.2

func IsCreateOrCloneElementCall(callee *ast.Node, pragma string, tc *checker.Checker) bool

IsCreateOrCloneElementCall reports whether the callee resolves to `<pragma>.createElement` / `<pragma>.cloneElement` (configured pragma) or — when `tc` is non-nil — a bare `createElement` / `cloneElement` identifier imported / destructured from the pragma module. Mirrors upstream `eslint-plugin-react`'s `isCreateCloneElement` predicate used by `no-array-index-key`, INCLUDING upstream's acceptance of optional chains (`React?.cloneElement(...)`) — upstream listens on `'CallExpression, OptionalCallExpression'` and gates on `node.type === 'MemberExpression' || node.type === 'OptionalMemberExpression'`.

Parens are skipped on the pragma sub-expression so `(React).cloneElement` is recognized (ESTree flattens parens). TS-only expression wrappers (`as` / `satisfies` / `<T>x` / `x!`) on the pragma identifier are NOT skipped — that would over-match relative to ESLint's JS-only AST and is a divergence we deliberately avoid.

func IsCreateReactClassObjectArg added in v0.5.0

func IsCreateReactClassObjectArg(obj *ast.Node, pragma, createClass string) bool

IsCreateReactClassObjectArg reports whether `obj` (an ObjectLiteralExpression) is the FIRST argument of a `<createClass>(...)` / `<pragma>.<createClass>(...)` call. Parens wrapping `obj` before it reaches the call argument position are transparent — tsgo preserves them while ESTree flattens — so `createReactClass(({...}))` still matches.

Pass the empty string for pragma / createClass to fall back to `DefaultReactPragma` / `DefaultReactCreateClass`. Returns false for any non-ObjectLiteralExpression input, for objects in non-argument positions, and for calls whose callee is not the configured createClass name.

func IsDOMComponent added in v0.5.0

func IsDOMComponent(element *ast.Node) bool

IsDOMComponent reports whether a JSX opening/self-closing element refers to an intrinsic (DOM) element like <div> or <svg:path>, rather than a user component like <Foo> or <Foo.Bar>.

Mirrors ESLint-plugin-react's `jsxUtil.isDOMComponent`: a tag name is intrinsic iff `elementType(node)` starts with a lowercase letter (regex `/^[a-z]/`). For member-expression tags (`<foo.bar>`, `<this.Foo>`) this means the classification is decided by the leftmost base identifier's first character — so `<foo.bar>` is DOM (matches ESLint, even though the runtime React behavior is "always user component"), while `<Foo.Bar>` is a user component.

func IsDestructuredFromPragmaImport added in v0.5.1

func IsDestructuredFromPragmaImport(ident *ast.Node, pragma string, tc *checker.Checker) bool

IsDestructuredFromPragmaImport mirrors upstream eslint-plugin-react's `lib/util/isDestructuredFromPragmaImport.js`: reports whether the Identifier `ident` (a bare callee like `memo`) was bound from the pragma module. Returns true when ident's local binding originated from any of:

  • `import { memo } from 'react'` (named import)
  • `import { memo as m } from 'react'` (named-import rename — checks the imported name, not the local alias)
  • `import * as React from 'react'`'s namespace + `const memo = React.memo`
  • `const { memo } = React` (object destructure of the pragma binding)
  • `const memo = React.memo` (member access via pragma binding)
  • `const { memo } = require('react')` (require destructure)
  • `const memo = require('react').memo` (require member access)

`pragma` is the React pragma name (e.g. "React") — the comparison against ImportDeclaration / require argument uses `strings.ToLower(pragma)` to match upstream's `pragma.toLocaleLowerCase()` semantic. `tc` may be nil — when no TypeChecker is available the function falls back to a syntax-only SourceFile-wide scan via `findPragmaBindingByName`. That fallback is strictly a subset of TC-based resolution (no scope precision) but covers the idiomatic top-level pragma-import patterns, keeping the observable wrapper-recognition behavior aligned with upstream in no-tsconfig modes.

func IsDetectedComponent added in v0.5.2

func IsDetectedComponent(node *ast.Node, pragma, createClass string, wrappers []ComponentWrapperEntry, tc *checker.Checker) bool

IsDetectedComponent reports whether `node` looks like a React component the upstream `Components.detect` pipeline would classify with confidence ≥ 2 — i.e. would surface in `components.list()`. Mirrors `components.get(node)` for the four AST kinds upstream's detection visits:

  • FunctionDeclaration / FunctionExpression / ArrowFunction (and the object-shorthand Method / Get / Set forms): defers to IsStatelessReactComponentWithWrappers, with a fallback for user-configured wrappers that the hardcoded memo/forwardRef branch wouldn't catch on its own.
  • ClassDeclaration / ClassExpression: an extends clause that resolves to `<pragma>.Component` / `Component`.
  • ObjectLiteralExpression: the argument shape of `<createClass>(...)` (ES5 component).
  • CallExpression: matches a configured wrapper, has a FunctionLike first argument, and is not a MemberExpression wrapper around a body whose root JSX tag refers to a sibling/outer detected component (`nodeWrapsComponent` gate — see WrapperWrapsKnownSiblingComponent).

Note that this function returns true for the inner FunctionLike of a pragma-wrapper call AND for the wrapper CallExpression itself — the same dual classification upstream produces (the inner arrow's `getStatelessComponent` redirects to the outer call, while the outer CallExpression listener also runs). Callers that need single-component identity must dedupe by node pointer or by remapping inner FunctionLike to its enclosing wrapper call (see no-multi-comp's collection pass for the canonical pattern).

func IsFirstLetterCapitalized added in v0.5.1

func IsFirstLetterCapitalized(s string) bool

IsFirstLetterCapitalized is the exported alias for the package-private helper. Mirrors eslint-plugin-react's `lib/util/isFirstLetterCapitalized.js` — strips leading underscores then compares `unicode.ToUpper(r) == r`. Non-cased characters (CJK, digits, emoji) count as "capitalized" because they have no upper/lower mapping. Use this for any parent-name / binding capitalization check that needs to align with upstream's component detection semantics.

func IsFunctionLikeForComponent added in v0.5.2

func IsFunctionLikeForComponent(node *ast.Node) bool

IsFunctionLikeForComponent reports whether `node` is a function-shaped node the React component-detection pipeline classifies as a "potential component" candidate. Covers FunctionDeclaration / FunctionExpression / ArrowFunction and the object-literal shorthand MethodDeclaration / GetAccessor / SetAccessor (upstream's ESTree shape exposes these as a `Property { method: true, value: FunctionExpression }`). Class methods share the same Kind values but are not function-shaped *components*; rule callers gate by parent / context where that matters.

func IsHookName added in v0.5.1

func IsHookName(name string) bool

IsHookName reports whether `name` matches the React hook naming convention. Returns false for empty input.

func IsInsideReactComponent added in v0.5.0

func IsInsideReactComponent(node *ast.Node, pragma, createClass string) bool

IsInsideReactComponent reports whether `node` is lexically inside a React component, applying the SCOPE-BASED detection semantic that upstream's `componentUtil.getParentES6Component(...) || componentUtil.getParentES5Component(...)` use directly (the pattern of `no-string-refs` and `no-access-state-in-setstate`).

**NOT equivalent to `GetEnclosingReactComponent != nil`**: the latter mimics `Components.set`'s free AST ancestor walk that crosses any non-React class. This helper applies the stricter ES6-stops-at-first- class rule. Pick based on the upstream rule's pattern:

  • Rule uses `Components.detect((context, components, utils) => ...)` and calls `components.set(node, ...)` / `components.get(...)` → use `GetEnclosingReactComponent`.

  • Rule calls `componentUtil.getParentES6Component` / `componentUtil.getParentES5Component` directly → use this helper (or `GetParentReactComponentScopeBased` for the node).

Pass empty strings for pragma/createClass to fall back to defaults.

func IsJsxElementLike added in v0.5.1

func IsJsxElementLike(node *ast.Node) bool

IsJsxElementLike reports whether node is a JsxElement or JsxSelfClosingElement — the two tsgo kinds that correspond to ESTree's single `JSXElement` type.

func IsJsxLike added in v0.5.1

func IsJsxLike(node *ast.Node) bool

IsJsxLike mirrors eslint-plugin-react's `jsxUtil.isJSX` — true for a JSX element (either tag form) or a JSX fragment.

func IsLowercaseFirstLetter added in v0.5.1

func IsLowercaseFirstLetter(s string) bool

IsLowercaseFirstLetter is the companion of IsFirstLetterCapitalized that matches upstream's exact lowercase-skip predicate from `lib/rules/no-unstable-nested-components.js`:

parentName[0] === parentName[0].toLowerCase()

Notably this is NOT the negation of IsFirstLetterCapitalized: this helper does NOT strip leading underscores, so `_Foo` is treated as lowercase here (the `_` round-trips through `ToLower`) even though IsFirstLetterCapitalized returns true for `_Foo` (after stripping `_`, `Foo` is capitalized). Both helpers exist because upstream uses each in different code paths — keep them paired.

func IsNodeFirstInLine added in v0.5.3

func IsNodeFirstInLine(sf *ast.SourceFile, node *ast.Node) bool

IsNodeFirstInLine reports whether node is the first non-whitespace (and non-comma) source character on its line. Walks back from the trimmed start over spaces, tabs, commas and CR; a leading newline (or start-of-file) means yes, anything else means no. The comma skip mirrors upstream's `getFirstNodeInLine` behaviour for array-literal siblings.

func IsObjectLiteralShorthandFunction added in v0.5.1

func IsObjectLiteralShorthandFunction(node *ast.Node) bool

IsObjectLiteralShorthandFunction reports whether `node` is a FunctionLike that, in ESTree, would be the inner FunctionExpression of a `Property { value: FunctionExpression }` — i.e. an object-literal shorthand method / getter / setter. Useful for callers that want to narrow diagnostic ranges to the parameter-list `(` (see ParamListOpenParenPos) so positions align with ESTree's reporting shape.

func IsPropWrapperCall added in v0.5.2

func IsPropWrapperCall(call *ast.Node, wrappers []PropWrapperEntry) bool

IsPropWrapperCall reports whether `call` is a CallExpression whose callee matches one of the user-configured `propWrapperFunctions` entries.

Supports:

  • bare identifier callees: `forbidExtraProps(...)`, `merge(...)` — match an entry with empty `Object`.
  • dotted-property callees: `Object.assign(...)`, `_.assign(...)` — match an entry whose `Object` and `Property` both equal the receiver and method names respectively.

`call` may be wrapped in parens / TS expression wrappers; the callee is unwrapped via `SkipExpressionWrappers`. Anything more complex (computed access, optional-chain wrappers around the callee head) is treated as not matching.

func IsStatelessReactComponent added in v0.5.0

func IsStatelessReactComponent(fn *ast.Node, pragma string) bool

IsStatelessReactComponent reports whether `fn` (a FunctionLike) looks like a React functional component. Mirrors eslint-plugin-react's `getStatelessComponent` decision tree:

  • FunctionDeclaration — component iff returns JSX/null AND either: (a) its own Identifier is capitalized, OR (b) it is anonymous AND carries the `export default` modifier (ESLint's `!node.id || capitalized(node.id.name)` condition).

  • FunctionExpression / ArrowFunction — component iff returns JSX/null AND either wrapped in a pragma component call OR in an "allowed position" AND the position-specific capitalization check passes:

  • Wrapped in `<pragma>.memo(...)` / `<pragma>.forwardRef(...)` / bare `memo(...)` / bare `forwardRef(...)` — always a component.

  • Allowed positions (VariableDeclarator, AssignmentExpression, PropertyAssignment, ReturnStatement, ExportAssignment, outer ArrowFunction body) gate everything else. A bare IIFE or any other CallExpression argument position is NOT allowed, matching upstream's `isInAllowedPositionForComponent` default-false branch.

  • Within an allowed position, specific capitalization rules apply per upstream: VariableDeclarator/PropertyAssignment use the binding name; `Id = fn` assignments use the LHS Identifier; MemberExpression LHS uses the rightmost property name (with `module.exports = ...` as a special blanket-true case); a named FunctionExpression defers to its own Identifier.

Pass the empty string for `pragma` to default to `DefaultReactPragma`.

This wrapper preserves the historical "no checker" call shape used by every other React rule. Pass a non-nil checker via `IsStatelessReactComponentWithChecker` to enable Identifier-through-scope resolution inside the JSX-return checks (relevant for any input where the function returns a name bound elsewhere — `return view` ↔ `let view = <div/>` etc).

func IsStatelessReactComponentWithChecker added in v0.5.1

func IsStatelessReactComponentWithChecker(fn *ast.Node, pragma string, tc *checker.Checker) bool

IsStatelessReactComponentWithChecker mirrors IsStatelessReactComponent and additionally threads `tc` into every isReturningJSX / isReturningJSXOrNull gate inside the decision tree. When `tc` is nil, all behavior matches `IsStatelessReactComponent` exactly (local-block initializer scan only).

The pragma-component-wrapper branch (Branch 11) uses the hardcoded default wrappers (`memo` / `forwardRef`, pragma-qualified or bare). To honor `settings.componentWrapperFunctions` here, use `IsStatelessReactComponentWithWrappers` instead.

func IsStatelessReactComponentWithWrappers added in v0.5.1

func IsStatelessReactComponentWithWrappers(fn *ast.Node, pragma string, tc *checker.Checker, wrappers []ComponentWrapperEntry) bool

IsStatelessReactComponentWithWrappers is the variant that consults a user-provided wrapper list when classifying the inner function of pragma-component-wrapper calls (Branch 11 of the decision tree).

Why this matters: `myMemo(() => null)` with `settings.componentWrapperFunctions: ['myMemo']` should classify the inner arrow as a stateless component (via the wrapper-arm of upstream's `getStatelessComponent`), so that the null-only return correctly triggers `isStatelessComponentReturningNull` and the rule SKIPs. With the hardcoded variant above, `myMemo` isn't recognized → the arrow isn't classified → the null-only skip never fires → the rule reports where upstream would not.

Pass `wrappers = nil` for hardcoded defaults; pass the configured `GetComponentWrapperFunctions(...)` list to honor user settings.

func JSXRootTagName added in v0.5.2

func JSXRootTagName(expr *ast.Node) string

JSXRootTagName returns the tag-name of a JsxElement / JsxSelfClosingElement (peeling paren / TS wrappers) when it's a plain Identifier, or "" otherwise. Member-expression tag-names (`<Foo.Bar />`) and namespaced names (`<svg:circle/>`) intentionally return "" — upstream's `getComponentNameFromJSXElement` only matches plain identifiers via the detected-components list keyed by the binding's local name.

func MakeNoMethodSetStateRule added in v0.5.2

func MakeNoMethodSetStateRule(cfg NoMethodSetStateConfig) rule.Rule

MakeNoMethodSetStateRule produces a rule that reports `this.setState(...)` calls whose enclosing class method, class field initializer, or object-literal property is keyed [NoMethodSetStateConfig.MethodName].

Mirrors upstream's `makeNoMethodSetStateRule` 1:1 in semantics — including the innermost-stopper search (`findLast(ancestors, ...)`), the function-depth counter that gates `disallow-in-func`, and the ESTree-shaped `'name' in callee.property` test (which we model with EsTreeName: any non-Identifier / non-PrivateIdentifier key yields "" and never matches).

All three of `no-did-mount-set-state`, `no-did-update-set-state`, and `no-will-update-set-state` are thin wrappers around this factory; do not inline these helpers in any new rule — extend the factory instead.

func MatchGlob added in v0.5.1

func MatchGlob(text, pattern string) bool

MatchGlob reports whether `text` matches the minimatch-style `pattern`. Returns false for empty `text`. Supports leading `!` whole-pattern negation: a pattern of `!X` matches everything except what `X` matches. `!!X` is treated as a literal pattern starting with `!` (matches `!X`), mirroring minimatch's odd-count-of-`!` rule.

func MatchesAnyComponentWrapper added in v0.5.1

func MatchesAnyComponentWrapper(call, fn *ast.Node, wrappers []ComponentWrapperEntry) bool

MatchesAnyComponentWrapper reports whether `call` matches any entry in `wrappers`, with `fn` as its first argument (paren / TS-wrapper transparent). Pass an empty pragma to default to "React"; the pragma is only consulted for entries whose `Object` is empty AND need to fall back to the configured pragma — but `DefaultComponentWrappers` already pre-fills the pragma form, so callers normally shouldn't need to thread pragma through twice.

Optional-chain handling mirrors upstream's `isPragmaComponentWrapper`:

  • Member-level optional (`React?.memo(arg)`) — recognized; Babel emits the callee as MemberExpression with `optional: true` and upstream's `callee.type === 'MemberExpression'` check still passes.

  • Call-level optional (`memo?.(arg)`) on a bare Identifier callee — recognized only against `IsUserConfigured: true` entries. Hardcoded bare-default entries (`memo` / `forwardRef` without pragma object) are upstream-gated by `isDestructuredFromPragmaImport`, which we cannot enforce without an import resolver. Restricting hardcoded bare defaults to non-optional matches keeps us conservative; user wrappers don't need that gate (they're explicit user opt-in).

func MatchesAnyComponentWrapperWithChecker added in v0.5.1

func MatchesAnyComponentWrapperWithChecker(call, fn *ast.Node, wrappers []ComponentWrapperEntry, pragma string, tc *checker.Checker) bool

MatchesAnyComponentWrapperWithChecker is the import-aware variant. When `tc` is non-nil and the callee is a bare Identifier matching a hardcoded bare default entry (`{Property: "memo"}` / `{Property: "forwardRef"}` from `DefaultComponentWrappers`), the callee's binding must additionally be destructured from / imported from / required from the pragma module (per `IsDestructuredFromPragmaImport`). This precisely mirrors upstream's

(!wrapperFunction.object ||
 (wrapperFunction.object === pragma &&
  this.isDestructuredFromPragmaImport(node, node.callee.name)))

gate. Without this, `memo(arrow)` would silently classify when `memo` is a user-defined function unrelated to React — leading to over-reports where upstream skips. Use this variant whenever a TypeChecker is available; otherwise the import-resolution check is skipped (matching the non-checker variant's conservative behavior — call-level optional rejected for hardcoded bare defaults).

func MethodNoopAtReactVersion added in v0.5.2

func MethodNoopAtReactVersion(major, minor, patch int) func(map[string]interface{}) bool

MethodNoopAtReactVersion returns a [NoMethodSetStateConfig.ShouldBeNoop] callback equivalent to upstream's `shouldBeNoop` for entries in `methodNoopsAsOf`: noop iff `settings.react.version` is explicitly set AND falls in the half-open range [major.minor.patch, 999.999.999).

The upper-bound 999.999.999 carve-out matches upstream — it is the "version absent" sentinel both upstream and rslint use, so a user who pins that string is treated as "version unpinned" and the rule stays active.

func NodeEndIndent added in v0.5.3

func NodeEndIndent(sf *ast.SourceFile, node *ast.Node, indentChar byte) int

NodeEndIndent returns the leading indent (count of `indentChar`) on the line containing the trimmed end of `node`. Steps one byte back from `End()` to land inside the node so that a node ending exactly at a newline is still attributed to its own last line.

func NodeStartIndent added in v0.5.3

func NodeStartIndent(sf *ast.SourceFile, node *ast.Node, indentChar byte) int

NodeStartIndent returns the leading indent (count of `indentChar`) on the line containing the trimmed start of `node`.

func NodeStartUTF16Column added in v0.5.3

func NodeStartUTF16Column(sf *ast.SourceFile, node *ast.Node) int

NodeStartUTF16Column returns the 0-based UTF-16 character column of the trimmed start of `node`. Used by indent-style rules whose option semantics are character-based (e.g. eslint-plugin-react's `jsx-indent-props` `'first'` mode, which aligns to the visual column of the first prop). Counting bytes here would diverge from upstream ESLint when the source contains multi-byte characters before the node.

func ParamListOpenParenPos added in v0.5.1

func ParamListOpenParenPos(sf *ast.SourceFile, node *ast.Node) int

ParamListOpenParenPos returns the source position of the `(` that opens `node`'s parameter list, or -1 when the position cannot be located. Walks tokens after `node.Name().End()` via the scanner — robust against type-parameter lists (`<T>(p: T)`) where the `(` is not contiguous with the name. Use this when narrowing a diagnostic range on an object-literal shorthand method / getter / setter so the report site aligns with ESTree's `Property { value: FunctionExpression }` shape (FE.loc.start at `(`).

`node` must be a MethodDeclaration / GetAccessor / SetAccessor (or anything with a non-nil `Name()`); other inputs return -1.

func ParseReactVersion added in v0.5.0

func ParseReactVersion(settings map[string]interface{}) (int, int, int)

ParseReactVersion returns the (major, minor, patch) triple of `settings.react.version`. When the setting is missing, not a string, empty, or not recognizable as a version, it defaults to (999, 999, 999) — matching eslint-plugin-react's `getReactVersionFromContext`, which treats an absent version as "latest".

func ReactVersionLessThan added in v0.5.0

func ReactVersionLessThan(settings map[string]interface{}, major, minor, patch int) bool

ReactVersionLessThan reports whether `settings.react.version` is strictly less than the given major.minor.patch. See ParseReactVersion for the default when the setting is missing.

func ReportIndentReplaceLeading added in v0.5.3

func ReportIndentReplaceLeading(ctx rule.RuleContext, node *ast.Node, needed, gotten int, indentChar byte, indentType string)

ReportIndentReplaceLeading emits a `wrongIndent` diagnostic anchored at `node` and provides an autofix that replaces the whitespace from the start of the node's line up to the node's trimmed start with `needed` repetitions of `indentChar`. This is the default fix shape used by upstream's `replaceTextRange([node.range[0] - node.loc.start.column, node.range[0]], …)` pattern.

When `needed` is negative (only reachable via a negative `indentSize` option such as `[-2]`), the diagnostic is emitted WITHOUT a fix. The message still reports the negative `needed` verbatim — that matches upstream ESLint, which calls `' '.repeat(needed)` inside its fix lambda; the lambda throws `RangeError`, ESLint discards the fix but keeps the diagnostic intact. Skipping the fix here avoids the `strings: negative Repeat count` panic in Go (which would crash the whole linter, not just this one rule).

func ResolveIdentifierInitializer added in v0.5.3

func ResolveIdentifierInitializer(ident *ast.Node, tc *checker.Checker) *ast.Node

ResolveIdentifierInitializer returns the value-side AST node that an Identifier reference is bound to, or nil when the binding cannot be determined.

  • When `tc` is non-nil, asks the TypeChecker for the resolved symbol's ValueDeclaration, then returns that declaration's `.Initializer` (only the const/let/var case — class / function declarations have no `Initializer` and aren't useful for JSX-return resolution). This is upstream-equivalent to `findVariableByName` because the TS resolver already follows the full lexical scope chain.

  • When `tc` is nil, falls back to scanning enclosing Block / SourceFile / ModuleBlock / CaseBlock statements for a `VariableStatement` declaring `name` — catches the common same-block initializer case without scope analysis.

func ReturnedJSXRootTagName added in v0.5.2

func ReturnedJSXRootTagName(fn *ast.Node) string

ReturnedJSXRootTagName extracts the root JSX tag name from a function's body — covers both the concise-body case (`() => <Foo/>`) and the block-body case where the FIRST top-level ReturnStatement is inspected. Returns empty string when the body doesn't return a JSX element directly.

func SkipExpressionWrappers added in v0.5.1

func SkipExpressionWrappers(node *ast.Node) *ast.Node

SkipExpressionWrappers is a paren-and-TS-type-wrapper-transparent variant of `ast.SkipParentheses`. It additionally peels back tsgo's TS-only expression wrappers that ESLint's ESTree never produces: `as`-expressions, `satisfies`-expressions, `<T>x` type assertions, and `x!` non-null assertions. Use it whenever a rule must reach the underlying expression regardless of whether the source uses any of those wrappers — e.g. when matching a callee identifier, a JSX tag base, or a return-statement argument that may sit behind a `(x as Foo)`.

func SkipExpressionWrappersUp added in v0.5.1

func SkipExpressionWrappersUp(node *ast.Node) *ast.Node

SkipExpressionWrappersUp is the parent-walk equivalent of `SkipExpressionWrappers`: starting from `node.Parent`, walks up while the current parent is a transparent expression wrapper (`()` / `as` / `satisfies` / `<T>x` / `x!`) and returns the first non-wrapper ancestor, or nil when no such ancestor exists. Mirrors what ESTree implicitly does by flattening these wrappers — three sites in this rule used to inline the loop; one helper keeps them in lockstep.

func SourceHasComponentNamedBefore added in v0.5.2

func SourceHasComponentNamedBefore(root *ast.Node, name string, before int) bool

SourceHasComponentNamedBefore scans `root`'s subtree for a sibling/outer component declaration whose name equals `name` and whose start position precedes `before`. Mirrors upstream's `getDetectedComponents` filter — only `class` declarations and arrow-assigned-to-VariableDeclarator declarations qualify; function declarations do NOT (upstream's filter in `Components.js getDetectedComponents` only retains those two kinds). The position gate replicates upstream's order-dependence: a sibling declared AFTER the use site has not yet been added to the components list when `isPragmaComponentWrapper` runs, so it must not match here either.

func UTF16Length added in v0.5.3

func UTF16Length(s string) int

UTF16Length returns the number of UTF-16 code units required to encode s. ASCII / BMP runes count as 1; runes outside the BMP (>= U+10000) count as 2 (surrogate pair). Use this when computing column positions that must agree with ESLint's `loc.column` semantics — Go's `len(s)` is byte length (UTF-8), which can over-count for multi-byte characters.

func WrapperWrapsKnownSiblingComponent added in v0.5.2

func WrapperWrapsKnownSiblingComponent(call *ast.Node, fn *ast.Node) bool

WrapperWrapsKnownSiblingComponent reports whether `call` is a MemberExpression-callee wrapper (e.g. `React.memo(arrow)`) whose FunctionLike argument's body returns JSX whose root tag-name matches a sibling/outer arrow-assigned-to-VariableDeclarator or ClassDeclaration in the same source file declared before `call`. Mirrors upstream's `nodeWrapsComponent` gate inside `isPragmaComponentWrapper`, which is intentionally name-based (not symbol-based) and only applied to the MemberExpression form of the wrapper. The bare-callee form (`memo(...)` after `import { memo } from 'react'`) is NOT gated this way upstream and must NOT be gated here either.

func WrongIndentMessage added in v0.5.3

func WrongIndentMessage(needed, gotten int, indentType string) rule.RuleMessage

WrongIndentMessage builds the standard `wrongIndent` rule message used by indent-style rules ported from eslint-plugin-react. The message text matches the upstream `Expected indentation of {needed} {type} {characters} but found {gotten}.` template; `characters` switches between "character" and "characters" based on whether `needed` is 1.

Types

type ComponentMap added in v0.5.1

type ComponentMap map[string][]string

ComponentMap maps a component tag name (e.g. "a", "Link") to the set of attribute names that identify its link target (e.g. ["href"] or ["to"]).

func DefaultFormComponents added in v0.5.1

func DefaultFormComponents() ComponentMap

DefaultFormComponents returns the default form-component map: {"form": ["action"]}.

func DefaultLinkComponents added in v0.5.1

func DefaultLinkComponents() ComponentMap

DefaultLinkComponents returns the default link-component map: {"a": ["href"]}.

func ReadComponentsFromSettings added in v0.5.1

func ReadComponentsFromSettings(settings map[string]interface{}, key, attrField, defaultAttr string, base ComponentMap) ComponentMap

ReadComponentsFromSettings extracts a component-name→attribute-list map from `settings.<key>`, matching upstream `util/linkComponents`.

Upstream builds the map via `new Map(DEFAULT.concat(settings[key]).map(…))`, where same-key entries use last-wins (replace) semantics. This function mirrors that: a settings entry for an already-present component replaces the base entry entirely.

Shapes accepted (each entry may appear standalone or as an element of an outer array, mirroring upstream's `DEFAULT.concat(settings[key] || [])`):

  • string: "Link" → {Link: [defaultAttr]}
  • {name, <attrField>}: <attrField> string or []str → {name: [attr…]}

`attrField` is "linkAttribute" for linkComponents and "formAttribute" for formComponents — upstream uses distinct field names for each category (`value.linkAttribute` vs `value.formAttribute`), so getting this wrong would silently fall back to the default attribute for every custom form component the user configures.

type ComponentWrapperEntry added in v0.5.1

type ComponentWrapperEntry struct {
	Object           string
	Property         string
	IsUserConfigured bool
}

ComponentWrapperEntry describes one user-configured component-wrapping call site. Either form is recognized:

  • `{property: "memo", object: "React"}` matches `<object>.<property>(fn)` calls. Empty `object` is treated as `DefaultReactPragma`.
  • `{property: "memo"}` matches bare `<property>(fn)` calls when `object` is empty.

Mirrors eslint-plugin-react's `settings.componentWrapperFunctions` — strings in the user setting expand to `{property: <s>}`, objects pass through.

`IsUserConfigured` distinguishes entries the user explicitly added via `settings.componentWrapperFunctions` from entries we inject as hardcoded defaults (memo / forwardRef, pragma-qualified or bare). Upstream's `isDestructuredFromPragmaImport` adds a runtime guard to bare default entries — they only match when the bare callee was destructure-imported from the pragma module. We have no import resolver, so we approximate by matching default bare entries on non-optional calls only, and matching user-configured bare entries freely (since they don't depend on import resolution).

func DefaultComponentWrappers added in v0.5.1

func DefaultComponentWrappers(pragma string) []ComponentWrapperEntry

DefaultComponentWrappers is the always-on wrapper list every React rule uses regardless of `settings.componentWrapperFunctions`. Mirrors upstream: `{property: 'memo', object: pragma}`, `{property: 'forwardRef', object: pragma}`, plus the bare `memo` / `forwardRef` aliases.

func GetComponentWrapperFunctions added in v0.5.1

func GetComponentWrapperFunctions(settings map[string]interface{}, pragma string) []ComponentWrapperEntry

GetComponentWrapperFunctions reads `settings.componentWrapperFunctions` and merges the user's additions on top of `DefaultComponentWrappers`. Accepted shapes per entry:

  • string: "myMemo" → {Property: "myMemo"}
  • object: {"property": "memo", "object": "React"} → {Object: "React", Property: "memo"}; "object" defaults to empty (bare call) when omitted
  • object with `"object": "<pragma>"` placeholder — upstream's `getWrapperFunctions` (Components.js) substitutes the placeholder with the configured pragma at read time, so users can write `{property: 'memo', object: '<pragma>'}` and have it match whichever pragma the file is configured with. We mirror that substitution exactly.

Unknown / malformed entries are silently ignored, matching upstream.

type NoMethodSetStateConfig added in v0.5.2

type NoMethodSetStateConfig struct {
	// RuleName is the registered rule name, e.g. "react/no-did-mount-set-state".
	RuleName string

	// MethodName is the lifecycle hook the rule guards against, e.g.
	// "componentDidMount". Stopper containers (class methods, class fields,
	// object-literal properties, accessors, constructors) whose key resolves
	// to this name — or to "UNSAFE_<MethodName>" when [ShouldCheckUnsafe]
	// returns true — are reported.
	MethodName string

	// ShouldCheckUnsafe gates the `UNSAFE_<MethodName>` alias. When nil or
	// returning false, only [MethodName] matches. Mirrors upstream's
	// `shouldCheckUnsafeCb`.
	ShouldCheckUnsafe func(settings map[string]interface{}) bool

	// ShouldBeNoop, when non-nil and returning true, makes the rule emit no
	// listeners — it produces no diagnostics regardless of source. Mirrors
	// upstream's `shouldBeNoop(context, methodName)` gate (the
	// `methodNoopsAsOf` map plus the `>= 999.999.999` upper-bound carve-out).
	ShouldBeNoop func(settings map[string]interface{}) bool
}

NoMethodSetStateConfig configures the rule produced by MakeNoMethodSetStateRule.

The fields mirror upstream's `makeNoMethodSetStateRule(methodName, shouldCheckUnsafeCb)` factory in eslint-plugin-react/lib/util/makeNoMethodSetStateRule.js, with `ShouldBeNoop` extracted as a separate hook so the `methodNoopsAsOf` map upstream encodes inline can be expressed per-rule on our side.

type PropWrapperEntry added in v0.5.2

type PropWrapperEntry struct {
	// Object is the receiver portion of a member-call wrapper (e.g.
	// `"Object"` for `Object.assign`). Empty for bare-identifier wrappers.
	Object string
	// Property is the function name (e.g. `"assign"` for `Object.assign`,
	// or `"forbidExtraProps"` for a bare-identifier wrapper).
	Property string
}

PropWrapperEntry encodes one entry of `settings.propWrapperFunctions`. The raw entries can be either a bare string (`"forbidExtraProps"`) or an `{object, property}` pair (`{ object: "Object", property: "assign" }` → matches `Object.assign(...)`). Both shapes are normalized to this struct.

func GetPropWrapperFunctions added in v0.5.2

func GetPropWrapperFunctions(settings map[string]interface{}) []PropWrapperEntry

GetPropWrapperFunctions reads `settings.propWrapperFunctions` from the rslint config and returns the parsed entries. Unknown shapes (a non-array value, an entry that's neither a string nor a `{object, property}` map, an entry with empty `property`) are silently dropped — this matches eslint-plugin-react's `propWrapperUtil` permissive parsing.

Jump to

Keyboard shortcuts

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