Files
wehub-resource-sync a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:33:42 +08:00

89 lines
2.9 KiB
Go

package languages
import (
sitter "github.com/zzet/gortex/internal/parser/tsitter"
)
// React higher-order-component classification. A PascalCase const assigned
// `memo(...)`, `forwardRef(...)`, `React.memo(...)`, `styled.tag`...`` or
// `styled(Base)`...`` is a component, not a plain variable — but the TS/JS
// extractor mints it as a bare KindVariable. reactHOCComponentKind recognizes
// the initializer shape so the variable visitor can stamp Meta["component"]
// and re-attribute the inline render function's JSX to the outer const.
// reactHOCComponentKind classifies a variable_declarator's initializer as a
// React HOC component. It returns the component_kind ("memo" / "forwardRef" /
// "styled") and, for memo/forwardRef, the inline render function whose body's
// JSX should be attributed to the outer component (nil for styled, whose
// argument is a CSS template). Returns "" when the initializer is not a HOC.
func reactHOCComponentKind(node *sitter.Node, src []byte) (kind string, renderFn *sitter.Node) {
declarator := node
if declarator != nil && declarator.Type() != "variable_declarator" {
// The variable visitor passes the enclosing lexical_declaration; descend
// to its declarator.
declarator = firstChildOfType(node, "variable_declarator")
}
if declarator == nil {
return "", nil
}
val := declarator.ChildByFieldName("value")
if val == nil || val.Type() != "call_expression" {
return "", nil
}
fn := val.ChildByFieldName("function")
if fn == nil {
return "", nil
}
switch fn.Type() {
case "identifier":
switch fn.Content(src) {
case "memo":
return "memo", reactHOCRenderFn(val)
case "forwardRef":
return "forwardRef", reactHOCRenderFn(val)
}
case "member_expression":
obj := fn.ChildByFieldName("object")
if obj != nil && obj.Content(src) == "styled" {
return "styled", nil // styled.div`...`
}
if obj != nil && obj.Content(src) == "React" {
if prop := fn.ChildByFieldName("property"); prop != nil {
switch prop.Content(src) {
case "memo":
return "memo", reactHOCRenderFn(val)
case "forwardRef":
return "forwardRef", reactHOCRenderFn(val)
}
}
}
case "call_expression":
// styled(Base)`...` — a tagged template whose tag is a styled() call.
if inner := fn.ChildByFieldName("function"); inner != nil && inner.Content(src) == "styled" {
return "styled", nil
}
}
return "", nil
}
// reactHOCRenderFn returns the first argument of a call when it is an inline
// arrow / function expression (the HOC's render function), else nil.
func reactHOCRenderFn(call *sitter.Node) *sitter.Node {
args := call.ChildByFieldName("arguments")
if args == nil {
return nil
}
for i, _nc := 0, int(args.NamedChildCount()); i < _nc; i++ {
a := args.NamedChild(i)
if a == nil {
continue
}
switch a.Type() {
case "arrow_function", "function_expression", "function":
return a
}
return nil // first argument is not an inline function
}
return nil
}