MCPcopy Create free account
hub / github.com/Effect-TS/tsgo / ExtractLayerGraph

Function ExtractLayerGraph

internal/layergraph/extract.go:23–229  ·  view source on GitHub ↗

ExtractLayerGraph builds a directed graph of Layer composition from the given AST nodes. It performs a DFS with a two-pass approach using an explicit work stack: - First pass: push children for processing - Second pass: link processed children into the graph

(
	tp *typeparser.TypeParser,
	c *checker.Checker,
	nodes []*ast.Node,
	sf *ast.SourceFile,
	opts ExtractLayerGraphOptions,
)

Source from the content-addressed store, hash-verified

21// - First pass: push children for processing
22// - Second pass: link processed children into the graph
23func ExtractLayerGraph(
24 tp *typeparser.TypeParser,
25 c *checker.Checker,
26 nodes []*ast.Node,
27 sf *ast.SourceFile,
28 opts ExtractLayerGraphOptions,
29) *graph.Graph[LayerGraphNodeInfo, LayerGraphEdgeInfo] {
30 g := graph.New[LayerGraphNodeInfo, LayerGraphEdgeInfo]()
31 nodeToGraphIndex := make(map[*ast.Node]graph.NodeIndex)
32 visitedNodes := make(map[*ast.Node]bool)
33 nodeInPipeContext := make(map[*ast.Node]bool)
34 depthBudget := make(map[*ast.Node]int)
35
36 // Resolve the Layer module import name for ExplodeOnlyLayerCalls checks.
37 layerModuleName := ""
38 if !opts.SkipExplode {
39 layerModuleName = findLayerModuleName(sf)
40 }
41
42 // Initialize the work stack with the root nodes.
43 stack := []workItem{}
44
45 appendNodeToVisit := func(n *ast.Node, depth int) {
46 depthBudget[n] = depth
47 stack = append(stack, workItem{node: n, depth: depth})
48 }
49 for _, node := range nodes {
50 appendNodeToVisit(node, opts.FollowSymbolsDepth)
51 }
52
53 addNode := func(n *ast.Node, info LayerGraphNodeInfo) graph.NodeIndex {
54 idx := g.AddNode(info)
55 nodeToGraphIndex[n] = idx
56 return idx
57 }
58
59 for len(stack) > 0 {
60 // Pop from the stack (LIFO).
61 item := stack[len(stack)-1]
62 stack = stack[:len(stack)-1]
63 current := item.node
64 currentDepth := depthBudget[current]
65
66 // Case 1: Pipe detection
67 if !opts.SkipExplode {
68 if pipeResult := tp.ParsePipeCall(current); pipeResult != nil {
69 if !visitedNodes[current] {
70 // First pass: push self back, then subject and args.
71 appendNodeToVisit(current, currentDepth)
72 appendNodeToVisit(pipeResult.Subject, currentDepth)
73 for _, arg := range pipeResult.Args {
74 appendNodeToVisit(arg, currentDepth)
75 nodeInPipeContext[arg] = true
76 }
77 visitedNodes[current] = true
78 } else {
79 // Second pass: collect child graph indices.
80 allChildren := make([]*ast.Node, 0, 1+len(pipeResult.Args))

Callers 6

ExtractLayerMagicMethod · 0.92
formatLayerHoverFunction · 0.92
tryBuildRefactorFunction · 0.92
tryPrepareRefactorFunction · 0.92

Calls 11

NewFunction · 0.92
findLayerModuleNameFunction · 0.85
collectChildIndicesFunction · 0.85
extractNodeInfoFunction · 0.85
removePartialChildrenFunction · 0.85
isLayerModuleCallFunction · 0.85
isSimpleIdentifierFunction · 0.85
getAdjustedNodeFunction · 0.85
AddNodeMethod · 0.80
ParsePipeCallMethod · 0.80
AddEdgeMethod · 0.80

Tested by

no test coverage detected