MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / resolve

Function resolve

src/resolution/frameworks/terraform.ts:58–112  ·  view source on GitHub ↗
(ref: UnresolvedRef, context: ResolutionContext)

Source from the content-addressed store, hash-verified

56 },
57
58 resolve(ref: UnresolvedRef, context: ResolutionContext): ResolvedRef | null {
59 if (ref.language !== 'terraform') return null;
60
61 const qname = ref.referenceName;
62 const refDir = dirOf(ref.filePath);
63
64 // --- module-boundary bridge: module.M:file / module.M:var.X / module.M:output.X ---
65 const scoped = qname.match(/^module\.([^.:\s]+):(.+)$/);
66 if (scoped) {
67 return resolveScopedModuleRef(ref, scoped[1]!, scoped[2]!, refDir, context);
68 }
69
70 const candidates = context.getNodesByQualifiedName(qname);
71 if (candidates.length === 0) return null;
72
73 // 1. Same directory — the only scope Terraform can actually reference.
74 const sameDir = candidates.filter((c) => dirOf(c.filePath) === refDir);
75 if (sameDir.length > 0) {
76 return {
77 original: ref,
78 targetNodeId: sameDir[0]!.id,
79 confidence: 0.95,
80 resolvedBy: 'framework',
81 };
82 }
83
84 // 2. `.tfvars` assignments set ROOT module variables, and var-files are
85 // routinely kept in a subdirectory (`envs/prod.tfvars`). Walk up to
86 // the nearest ancestor directory that declares the variable.
87 if (ref.filePath.endsWith('.tfvars') && qname.startsWith('var.')) {
88 const up = nearestAncestorMatch(candidates, refDir);
89 if (up) {
90 return { original: ref, targetNodeId: up.id, confidence: 0.9, resolvedBy: 'framework' };
91 }
92 }
93
94 // 2b. Provider configurations are the one construct Terraform inherits
95 // across the module tree: they're declared in the root (or a parent)
96 // module and passed down, so `provider = aws.east` inside a child
97 // module legitimately names a configuration declared above it.
98 if (qname.startsWith('provider.')) {
99 const configs = candidates.filter((c) => c.kind === 'namespace');
100 const up = nearestAncestorMatch(configs, refDir);
101 if (up) {
102 return { original: ref, targetNodeId: up.id, confidence: 0.9, resolvedBy: 'framework' };
103 }
104 return null;
105 }
106
107 // 3. No same-directory declaration → no edge. A candidate in another
108 // module directory is never the real target (cross-module access only
109 // exists through module.M inputs/outputs, bridged above), and a wrong
110 // edge is worse than none.
111 return null;
112 },
113};
114
115/** Nearest candidate walking UP the directory tree from refDir (exclusive). */

Callers

nothing calls this directly

Calls 4

resolveScopedModuleRefFunction · 0.85
nearestAncestorMatchFunction · 0.85
dirOfFunction · 0.70

Tested by

no test coverage detected