Documentation
¶
Index ¶
- Constants
- func ExtendsReactComponent(classNode *ast.Node, pragma string) bool
- func ExtendsReactPureComponent(classNode *ast.Node, pragma string) bool
- 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) *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 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 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 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 IsFirstLetterCapitalized(s string) 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 IsObjectLiteralShorthandFunction(node *ast.Node) 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 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 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 SkipExpressionWrappers(node *ast.Node) *ast.Node
- func SkipExpressionWrappersUp(node *ast.Node) *ast.Node
- type ComponentMap
- type ComponentWrapperEntry
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 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 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
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 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 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 (only `*` and `?` wildcards recognized; every other regex metacharacter is literally escaped) into a fully anchored regular expression. Mirrors the subset of minimatch behavior eslint-plugin-react relies on for `propNamePattern`-style options — sufficient for `render*`, `*Renderer`, etc.
Compilation is cached per-pattern; the returned `*regexp.Regexp` is safe to share across goroutines.
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 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 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 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 contained within a React component — either an ES5 component (object literal passed as an argument to `<createClass>(...)` / `<pragma>.<createClass>(...)`) or an ES6 component (ClassDeclaration / ClassExpression extending Component or PureComponent, optionally qualified by pragma).
Pass the empty string for pragma/createClass to fall back to `DefaultReactPragma` / `DefaultReactCreateClass`.
Mirrors eslint-plugin-react's componentUtil:
ES6 path: only the nearest enclosing class decides component status (matching `getParentES6Component`'s `while scope.type !== 'class'`). A non-component class does not "pass through" to let an outer component class match — this prevents false positives like a non-React inner class nested inside a React class.
ES5 path: `this` / `this.refs` must occur inside some function, whose ObjectExpression parent is the argument to `<createClass>(...)`. We approximate this by requiring that an enclosing function has been passed on the walk up before an ObjectExpression is accepted — which rules out pathological cases like `createReactClass({ x: this.refs.y })` where `this` is not inside any function (ESLint's scope walk returns null for that too).
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 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 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 MatchGlob ¶ added in v0.5.1
MatchGlob is the fast path equivalent of `GlobToRegex(pattern).MatchString(text)`, returning false for empty `text`.
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 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 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.
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
Unknown / malformed entries are silently ignored, matching upstream.