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
96 lines
2.8 KiB
Go
96 lines
2.8 KiB
Go
package resolver
|
|
|
|
import "github.com/zzet/gortex/internal/graph"
|
|
|
|
// expoBridgeVia marks a synthesized JS→Expo-native call edge.
|
|
const expoBridgeVia = "expo.bridge"
|
|
|
|
// ResolveExpoModuleBridge is the framework-dispatch synthesizer for Expo
|
|
// Modules. The Swift/Kotlin extractors stamp expo_module + expo_method on
|
|
// synthetic method nodes parsed from the Expo DSL (Name / Function /
|
|
// AsyncFunction). The JS/TS extractor already emits an rn-native
|
|
// placeholder call edge (Meta["via"]="rn.native", rn_module + rn_method)
|
|
// for `requireNativeModule('Foo').bar()` — the canonical Expo JS consumer
|
|
// form. This pass joins them: for each such JS call it synthesizes a calls
|
|
// edge to every Expo native implementation of that (module, method).
|
|
//
|
|
// Full recompute and idempotent: graph.AddEdge dedupes by key,
|
|
// graph.EvictFile drops the edge in both directions on reindex. Edges
|
|
// ride at ast_inferred with synthesizer provenance.
|
|
//
|
|
// Returns the number of Expo bridge edges synthesized.
|
|
func ResolveExpoModuleBridge(g graph.Store) int {
|
|
if g == nil {
|
|
return 0
|
|
}
|
|
|
|
type modKey struct{ module, method string }
|
|
expoByKey := map[modKey][]*graph.Node{}
|
|
for _, n := range nodesByKindsOrAll(g, graph.KindMethod) {
|
|
if n == nil || n.Meta == nil {
|
|
continue
|
|
}
|
|
mod, _ := n.Meta["expo_module"].(string)
|
|
meth, _ := n.Meta["expo_method"].(string)
|
|
if mod == "" || meth == "" {
|
|
continue
|
|
}
|
|
expoByKey[modKey{mod, meth}] = append(expoByKey[modKey{mod, meth}], n)
|
|
}
|
|
if len(expoByKey) == 0 {
|
|
return 0
|
|
}
|
|
|
|
type pairKey struct{ from, to string }
|
|
seenPair := map[pairKey]bool{}
|
|
var batch []*graph.Edge
|
|
synthesized := 0
|
|
for e := range g.EdgesByKind(graph.EdgeCalls) {
|
|
if e == nil || e.Meta == nil || e.From == "" {
|
|
continue
|
|
}
|
|
if v, _ := e.Meta["via"].(string); v != rnNativeVia {
|
|
continue
|
|
}
|
|
mod, _ := e.Meta["rn_module"].(string)
|
|
meth, _ := e.Meta["rn_method"].(string)
|
|
if mod == "" || meth == "" {
|
|
continue
|
|
}
|
|
for _, native := range expoByKey[modKey{mod, meth}] {
|
|
if native.ID == "" || native.ID == e.From {
|
|
continue
|
|
}
|
|
pk := pairKey{from: e.From, to: native.ID}
|
|
if seenPair[pk] {
|
|
continue
|
|
}
|
|
seenPair[pk] = true
|
|
batch = append(batch, &graph.Edge{
|
|
From: e.From,
|
|
To: native.ID,
|
|
Kind: graph.EdgeCalls,
|
|
FilePath: e.FilePath,
|
|
Line: e.Line,
|
|
Confidence: 0.6,
|
|
ConfidenceLabel: graph.ConfidenceLabelFor(graph.EdgeCalls, 0.6),
|
|
Origin: graph.OriginASTInferred,
|
|
Meta: map[string]any{
|
|
"via": expoBridgeVia,
|
|
"expo_module": mod,
|
|
"expo_method": meth,
|
|
"native_language": native.Language,
|
|
MetaSynthesizedBy: SynthExpoModules,
|
|
MetaProvenance: ProvenanceHeuristic,
|
|
},
|
|
})
|
|
synthesized++
|
|
}
|
|
}
|
|
|
|
for _, e := range batch {
|
|
g.AddEdge(e)
|
|
}
|
|
return synthesized
|
|
}
|