Documentation
¶
Index ¶
- Constants
- func ApplyData(template string, data map[string]string) string
- func BindingIdentifierName(n *ast.Node) string
- func CheckUnsafeAtReactVersion(major, minor, patch int) func(map[string]interface{}) bool
- func ClassHasMethodNamed(classNode *ast.Node, methodName string) bool
- func ClassKeywordStart(text string, node *ast.Node) int
- func EnclosingClass(node *ast.Node) *ast.Node
- func EntityNameRightmost(name *ast.Node) *ast.Node
- func EsTreeName(nameNode *ast.Node) string
- func ExtendsReactComponent(classNode *ast.Node, pragma string) bool
- func ExtendsReactPureComponent(classNode *ast.Node, pragma string) bool
- func FirstParamType(fn *ast.Node) *ast.Node
- func FunctionBody(fn *ast.Node) *ast.Node
- func FunctionParameters(fn *ast.Node) []*ast.Node
- func FunctionReturnsJSX(fn *ast.Node, pragma string) bool
- func FunctionReturnsJSXOrNull(fn *ast.Node, pragma string) bool
- func FunctionReturnsJSXOrNullWithChecker(fn *ast.Node, pragma string, tc *checker.Checker) bool
- func FunctionReturnsJSXWithChecker(fn *ast.Node, pragma string, tc *checker.Checker) bool
- func GetEnclosingReactComponent(node *ast.Node, pragma, createClass string) *ast.Node
- func GetEnclosingReactComponentOrStateless(node *ast.Node, pragma, createClass string, wrappers []ComponentWrapperEntry) *ast.Node
- func GetJsxChildren(parent *ast.Node) []*ast.Node
- func GetJsxElementAttributes(element *ast.Node) []*ast.Node
- func GetJsxElementTypeString(node *ast.Node) string
- func GetJsxParentElement(attr *ast.Node) *ast.Node
- func GetJsxPropName(node *ast.Node) string
- func GetJsxTagBaseIdentifier(tagName *ast.Node) *ast.Node
- func GetJsxTagName(element *ast.Node) *ast.Node
- func GetParentReactComponentScopeBased(node *ast.Node, pragma, createClass string) *ast.Node
- func GetParentReactComponentScopeBasedOrStateless(node *ast.Node, pragma, createClass string, wrappers []ComponentWrapperEntry) *ast.Node
- func GetParentStatelessComponent(node *ast.Node, pragma string, wrappers []ComponentWrapperEntry) *ast.Node
- func GetReactCreateClass(settings map[string]interface{}) string
- func GetReactFragmentPragma(settings map[string]interface{}) string
- func GetReactPragma(settings map[string]interface{}) string
- func GlobToRegex(pattern string) *regexp.Regexp
- func HorizontalWhitespacePrefix(s string) string
- func IdentifierOrPrivateName(name *ast.Node) string
- func IndentLeading(text string, lineMap []core.TextPos, pos int, indentChar byte) int
- func IndentLineStart(lineMap []core.TextPos, pos int) int
- func IsCasedLowercaseFirstLetter(s string) bool
- func IsCreateClassCall(call *ast.CallExpression, pragma, createClass string) bool
- func IsCreateElementCall(callee *ast.Node, pragma string) bool
- func IsCreateElementCallWithChecker(callee *ast.Node, pragma string, tc *checker.Checker) bool
- func IsCreateOrCloneElementCall(callee *ast.Node, pragma string, tc *checker.Checker) bool
- func IsCreateReactClassObjectArg(obj *ast.Node, pragma, createClass string) bool
- func IsDOMComponent(element *ast.Node) bool
- func IsDestructuredFromPragmaImport(ident *ast.Node, pragma string, tc *checker.Checker) bool
- func IsDetectedComponent(node *ast.Node, pragma, createClass string, wrappers []ComponentWrapperEntry, ...) bool
- func IsFirstLetterCapitalized(s string) bool
- func IsFunctionLikeForComponent(node *ast.Node) bool
- func IsHookName(name string) bool
- func IsInsideReactComponent(node *ast.Node, pragma, createClass string) bool
- func IsJsxElementLike(node *ast.Node) bool
- func IsJsxLike(node *ast.Node) bool
- func IsLowercaseFirstLetter(s string) bool
- func IsNodeFirstInLine(sf *ast.SourceFile, node *ast.Node) bool
- func IsObjectLiteralShorthandFunction(node *ast.Node) bool
- func IsPropWrapperCall(call *ast.Node, wrappers []PropWrapperEntry) bool
- func IsStatelessReactComponent(fn *ast.Node, pragma string) bool
- func IsStatelessReactComponentWithChecker(fn *ast.Node, pragma string, tc *checker.Checker) bool
- func IsStatelessReactComponentWithWrappers(fn *ast.Node, pragma string, tc *checker.Checker, ...) bool
- func JSXRootTagName(expr *ast.Node) string
- func MakeNoMethodSetStateRule(cfg NoMethodSetStateConfig) rule.Rule
- func MatchGlob(text, pattern string) bool
- func MatchesAnyComponentWrapper(call, fn *ast.Node, wrappers []ComponentWrapperEntry) bool
- func MatchesAnyComponentWrapperWithChecker(call, fn *ast.Node, wrappers []ComponentWrapperEntry, pragma string, ...) bool
- func MethodNoopAtReactVersion(major, minor, patch int) func(map[string]interface{}) bool
- func NodeEndIndent(sf *ast.SourceFile, node *ast.Node, indentChar byte) int
- func NodeStartIndent(sf *ast.SourceFile, node *ast.Node, indentChar byte) int
- func NodeStartUTF16Column(sf *ast.SourceFile, node *ast.Node) int
- func ParamListOpenParenPos(sf *ast.SourceFile, node *ast.Node) int
- func ParseReactVersion(settings map[string]interface{}) (int, int, int)
- func ReactVersionLessThan(settings map[string]interface{}, major, minor, patch int) bool
- func ReportIndentReplaceLeading(ctx rule.RuleContext, node *ast.Node, needed, gotten int, indentChar byte, ...)
- func ResolveIdentifierInitializer(ident *ast.Node, tc *checker.Checker) *ast.Node
- func ReturnedJSXRootTagName(fn *ast.Node) string
- func SkipExpressionWrappers(node *ast.Node) *ast.Node
- func SkipExpressionWrappersUp(node *ast.Node) *ast.Node
- func SourceHasComponentNamedBefore(root *ast.Node, name string, before int) bool
- func UTF16Length(s string) int
- func WrapperWrapsKnownSiblingComponent(call *ast.Node, fn *ast.Node) bool
- func WrongIndentMessage(needed, gotten int, indentType string) rule.RuleMessage
- type ComponentMap
- type ComponentWrapperEntry
- type NoMethodSetStateConfig
- type PropWrapperEntry
Constants ¶
const DefaultReactCreateClass = "createReactClass"
DefaultReactCreateClass is the fallback ES5 factory name when `settings.react.createClass` is not configured, matching eslint-plugin-react.
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
FunctionReturnsJSXWithChecker is the TypeChecker-aware strict variant. See FunctionReturnsJSXOrNullWithChecker for the resolution semantics.
func GetEnclosingReactComponent ¶ added in v0.5.0
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
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
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
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
GetJsxParentElement returns the JsxOpeningElement or JsxSelfClosingElement that owns the given JsxAttribute (or JsxSpreadAttribute), or nil if not applicable.
func GetJsxPropName ¶
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
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
GetJsxTagName returns the tag-name node of a JsxOpeningElement or JsxSelfClosingElement, or nil for other kinds.
func GetParentReactComponentScopeBased ¶ added in v0.5.2
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
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
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
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
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
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
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
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
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
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 ¶
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
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
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
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
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
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
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
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
IsHookName reports whether `name` matches the React hook naming convention. Returns false for empty input.
func IsInsideReactComponent ¶ added in v0.5.0
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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.