-
Notifications
You must be signed in to change notification settings - Fork 573
Expand file tree
/
Copy pathcomponent_references.go
More file actions
73 lines (63 loc) · 2.66 KB
/
component_references.go
File metadata and controls
73 lines (63 loc) · 2.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package controller
import (
"log/slog"
"github.com/grafana/alloy/internal/dag"
"github.com/grafana/alloy/internal/featuregate"
astutil "github.com/grafana/alloy/internal/util/ast"
"github.com/grafana/alloy/syntax/ast"
"github.com/grafana/alloy/syntax/diag"
"github.com/grafana/alloy/syntax/vm"
)
// ComponentReferences returns the list of references a component is making to
// other components.
func ComponentReferences(cn dag.Node, g *dag.Graph, l *slog.Logger, scope *vm.Scope, minStability featuregate.Stability) ([]astutil.Reference, diag.Diagnostics) {
var (
traversals []astutil.Traversal
diags diag.Diagnostics
)
switch cn := cn.(type) {
case BlockNode:
if cn.Block() != nil {
traversals = astutil.TraversalsFromBody(cn.Block().Body)
}
}
refs := make([]astutil.Reference, 0, len(traversals))
for _, t := range traversals {
ref, resolveDiags := astutil.ResolveTraversal(t, g)
componentRefMatch := !resolveDiags.HasErrors()
// we look for a match in the provided scope and the stdlib
_, scopeMatch := scope.Lookup(t[0].Name)
if !componentRefMatch && !scopeMatch {
// The traversal for the foreach node is used at the foreach level to access the references from outside of the foreach block.
// This is quite handy but not perfect because:
// - it fails with the var
// - it fails at the root level to link two components that are inside of the template (because they are not evaluated at the root level)
// Both cases should be ignored at the linking level, that's the diags are ignored here.
// This is not super clean, but it should not create any problem since that the errors will be caught either during evaluation or while linking components
// inside of the foreach.
if _, ok := cn.(*ForeachConfigNode); !ok {
diags = append(diags, resolveDiags...)
}
continue
}
if componentRefMatch {
if scope.IsStdlibIdentifiers(t[0].Name) {
l.Warn("a component is shadowing an existing stdlib name", "component", ref.Target.NodeID(), "stdlib_name", t[0].Name)
}
refs = append(refs, ref)
} else if scope.IsStdlibDeprecated(t[0].Name) {
l.Warn("this stdlib function is deprecated; please refer to the documentation for updated usage and alternatives", "function", t[0].Name)
} else if funcName := t.String(); scope.IsStdlibExperimental(funcName) {
if err := featuregate.CheckAllowed(featuregate.StabilityExperimental, minStability, funcName); err != nil {
diags = append(diags, diag.Diagnostic{
Severity: diag.SeverityLevelError,
Message: err.Error(),
StartPos: ast.StartPos(t[0]).Position(),
EndPos: ast.StartPos(t[len(t)-1]).Position(),
})
continue
}
}
}
return refs, diags
}