chore: import upstream snapshot with attribution
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
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
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package languages
|
||||
|
||||
import (
|
||||
"github.com/zzet/gortex/internal/graph"
|
||||
"github.com/zzet/gortex/internal/parser"
|
||||
sitter "github.com/zzet/gortex/internal/parser/tsitter"
|
||||
)
|
||||
|
||||
// captureReactContextRefs emits a placeholder reference edge from a component
|
||||
// to the context object it reads via `useContext(SomeContext)`. The TS/JS
|
||||
// extractor records the `useContext` callee but drops the context-object
|
||||
// argument, so without this the React resolver has nothing to bind a
|
||||
// `useContext(AuthContext)` site to its /context/ definition. The edge is
|
||||
// tagged `via=react_context` so the resolver treats it as a context reference
|
||||
// regardless of the identifier's suffix. Runs at the tail of Extract.
|
||||
func captureReactContextRefs(result *parser.ExtractionResult, root *sitter.Node, filePath string, src []byte) {
|
||||
if root == nil || result == nil {
|
||||
return
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
expressWalk(root, func(c *sitter.Node) {
|
||||
if c.Type() != "call_expression" {
|
||||
return
|
||||
}
|
||||
fn := c.ChildByFieldName("function")
|
||||
if fn == nil || fn.Type() != "identifier" || fn.Content(src) != "useContext" {
|
||||
return
|
||||
}
|
||||
args := c.ChildByFieldName("arguments")
|
||||
if args == nil {
|
||||
return
|
||||
}
|
||||
ctx := reactFirstIdentArg(args, src)
|
||||
if ctx == "" {
|
||||
return
|
||||
}
|
||||
line := int(c.StartPoint().Row) + 1
|
||||
from := reactEnclosingFuncID(result.Nodes, line)
|
||||
if from == "" {
|
||||
return
|
||||
}
|
||||
key := from + "\x00" + ctx
|
||||
if seen[key] {
|
||||
return
|
||||
}
|
||||
seen[key] = true
|
||||
result.Edges = append(result.Edges, &graph.Edge{
|
||||
From: from, To: "unresolved::" + ctx, Kind: graph.EdgeReferences,
|
||||
FilePath: filePath, Line: line, Origin: graph.OriginASTInferred,
|
||||
Meta: map[string]any{"via": "react_context", "context_name": ctx},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// reactFirstIdentArg returns the first call argument when it is a bare
|
||||
// identifier (the context object passed to useContext), else "".
|
||||
func reactFirstIdentArg(args *sitter.Node, src []byte) string {
|
||||
for i, _nc := 0, int(args.NamedChildCount()); i < _nc; i++ {
|
||||
a := args.NamedChild(i)
|
||||
if a == nil {
|
||||
continue
|
||||
}
|
||||
if a.Type() == "identifier" {
|
||||
if name := a.Content(src); isSimpleJSIdent(name) {
|
||||
return name
|
||||
}
|
||||
}
|
||||
return "" // first arg isn't a plain identifier (e.g. a member expression)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// reactEnclosingFuncID returns the ID of the innermost function/method node
|
||||
// whose line range contains line, or "" when none does.
|
||||
func reactEnclosingFuncID(nodes []*graph.Node, line int) string {
|
||||
best := ""
|
||||
bestSpan := 1 << 30
|
||||
for _, n := range nodes {
|
||||
if n == nil {
|
||||
continue
|
||||
}
|
||||
if n.Kind != graph.KindFunction && n.Kind != graph.KindMethod {
|
||||
continue
|
||||
}
|
||||
if n.StartLine <= line && line <= n.EndLine {
|
||||
if span := n.EndLine - n.StartLine; span < bestSpan {
|
||||
bestSpan = span
|
||||
best = n.ID
|
||||
}
|
||||
}
|
||||
}
|
||||
return best
|
||||
}
|
||||
Reference in New Issue
Block a user