Skip to content

Commit c0b1fe5

Browse files
authored
Export dynvar.ref as Ref with all its fields and methods (#3385)
This is a useful utility to extract references from the tree to build a DAG. Planning to use this in direct deployment.
1 parent 8801366 commit c0b1fe5

File tree

3 files changed

+38
-38
lines changed

3 files changed

+38
-38
lines changed

libs/dyn/dynvar/ref.go

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,21 @@ var (
1515
re = regexp.MustCompile(fmt.Sprintf(`\$\{(%s(\.%s(\[[0-9]+\])*)*(\[[0-9]+\])*)\}`, baseVarDef, baseVarDef))
1616
)
1717

18-
// ref represents a variable reference.
18+
// Ref represents a variable reference.
1919
// It is a string [dyn.Value] contained in a larger [dyn.Value].
2020
// Its path within the containing [dyn.Value] is also stored.
21-
type ref struct {
21+
type Ref struct {
2222
// Original value.
23-
value dyn.Value
23+
Value dyn.Value
2424

2525
// String value in the original [dyn.Value].
26-
str string
26+
Str string
2727

2828
// Matches of the variable reference in the string.
29-
matches [][]string
29+
Matches [][]string
3030
}
3131

32-
// newRef returns a new ref if the given [dyn.Value] contains a string
32+
// NewRef returns a new Ref if the given [dyn.Value] contains a string
3333
// with one or more variable references. It returns false if the given
3434
// [dyn.Value] does not contain variable references.
3535
//
@@ -38,39 +38,39 @@ type ref struct {
3838
// - "${a.b.c}"
3939
// - "${a.b[0].c}"
4040
// - "${a} ${b} ${c}"
41-
func newRef(v dyn.Value) (ref, bool) {
41+
func NewRef(v dyn.Value) (Ref, bool) {
4242
s, ok := v.AsString()
4343
if !ok {
44-
return ref{}, false
44+
return Ref{}, false
4545
}
4646

4747
// Check if the string contains any variable references.
4848
m := re.FindAllStringSubmatch(s, -1)
4949
if len(m) == 0 {
50-
return ref{}, false
50+
return Ref{}, false
5151
}
5252

53-
return ref{
54-
value: v,
55-
str: s,
56-
matches: m,
53+
return Ref{
54+
Value: v,
55+
Str: s,
56+
Matches: m,
5757
}, true
5858
}
5959

60-
// isPure returns true if the variable reference contains a single
60+
// IsPure returns true if the variable reference contains a single
6161
// variable reference and nothing more. We need this so we can
6262
// interpolate values of non-string types (i.e. it can be substituted).
63-
func (v ref) isPure() bool {
63+
func (v Ref) IsPure() bool {
6464
// Need single match, equal to the incoming string.
65-
if len(v.matches) == 0 || len(v.matches[0]) == 0 {
65+
if len(v.Matches) == 0 || len(v.Matches[0]) == 0 {
6666
panic("invalid variable reference; expect at least one match")
6767
}
68-
return v.matches[0][0] == v.str
68+
return v.Matches[0][0] == v.Str
6969
}
7070

71-
func (v ref) references() []string {
71+
func (v Ref) References() []string {
7272
var out []string
73-
for _, m := range v.matches {
73+
for _, m := range v.Matches {
7474
out = append(out, m[1])
7575
}
7676
return out
@@ -87,16 +87,16 @@ func ContainsVariableReference(s string) bool {
8787
// If s is a pure variable reference, this function returns the corresponding
8888
// dyn.Path. Otherwise, it returns false.
8989
func PureReferenceToPath(s string) (dyn.Path, bool) {
90-
ref, ok := newRef(dyn.V(s))
90+
ref, ok := NewRef(dyn.V(s))
9191
if !ok {
9292
return nil, false
9393
}
9494

95-
if !ref.isPure() {
95+
if !ref.IsPure() {
9696
return nil, false
9797
}
9898

99-
p, err := dyn.NewPathFromString(ref.references()[0])
99+
p, err := dyn.NewPathFromString(ref.References()[0])
100100
if err != nil {
101101
return nil, false
102102
}

libs/dyn/dynvar/ref_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import (
99
)
1010

1111
func TestNewRefNoString(t *testing.T) {
12-
_, ok := newRef(dyn.V(1))
12+
_, ok := NewRef(dyn.V(1))
1313
require.False(t, ok, "should not match non-string")
1414
}
1515

@@ -23,9 +23,9 @@ func TestNewRefValidPattern(t *testing.T) {
2323
"${hello_world.world-_world}": {"hello_world.world-_world"},
2424
"${hello_world.world_-world}": {"hello_world.world_-world"},
2525
} {
26-
ref, ok := newRef(dyn.V(in))
26+
ref, ok := NewRef(dyn.V(in))
2727
require.True(t, ok, "should match valid pattern: %s", in)
28-
assert.Equal(t, refs, ref.references())
28+
assert.Equal(t, refs, ref.References())
2929
}
3030
}
3131

@@ -42,7 +42,7 @@ func TestNewRefInvalidPattern(t *testing.T) {
4242
"${helloworld.9world-world}", // interpolated second section shouldn't start with number
4343
}
4444
for _, v := range invalid {
45-
_, ok := newRef(dyn.V(v))
45+
_, ok := NewRef(dyn.V(v))
4646
require.False(t, ok, "should not match invalid pattern: %s", v)
4747
}
4848
}

libs/dyn/dynvar/resolve.go

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ type resolver struct {
4646
in dyn.Value
4747
fn Lookup
4848

49-
refs map[string]ref
49+
refs map[string]Ref
5050
resolved map[string]dyn.Value
5151

5252
// Memoization for lookups.
@@ -73,11 +73,11 @@ func (r resolver) run() (out dyn.Value, err error) {
7373
}
7474

7575
func (r *resolver) collectVariableReferences() (err error) {
76-
r.refs = make(map[string]ref)
76+
r.refs = make(map[string]Ref)
7777

7878
// First walk the input to gather all values with a variable reference.
7979
_, err = dyn.Walk(r.in, func(p dyn.Path, v dyn.Value) (dyn.Value, error) {
80-
ref, ok := newRef(v)
80+
ref, ok := NewRef(v)
8181
if !ok {
8282
// Skip values without variable references.
8383
return v, nil
@@ -113,9 +113,9 @@ func (r *resolver) resolveVariableReferences() (err error) {
113113
return nil
114114
}
115115

116-
func (r *resolver) resolveRef(ref ref, seen []string) (dyn.Value, error) {
116+
func (r *resolver) resolveRef(ref Ref, seen []string) (dyn.Value, error) {
117117
// This is an unresolved variable reference.
118-
deps := ref.references()
118+
deps := ref.References()
119119

120120
// Resolve each of the dependencies, then interpolate them in the ref.
121121
resolved := make([]dyn.Value, len(deps))
@@ -145,19 +145,19 @@ func (r *resolver) resolveRef(ref ref, seen []string) (dyn.Value, error) {
145145
}
146146

147147
// Interpolate the resolved values.
148-
if ref.isPure() && complete {
148+
if ref.IsPure() && complete {
149149
// If the variable reference is pure, we can substitute it.
150150
// This is useful for interpolating values of non-string types.
151151
//
152152
// Note: we use the location of the variable reference to preserve the information
153153
// of where it is used. This also means that relative path resolution is done
154154
// relative to where a variable is used, not where it is defined.
155155
//
156-
return dyn.NewValue(resolved[0].Value(), ref.value.Locations()), nil
156+
return dyn.NewValue(resolved[0].Value(), ref.Value.Locations()), nil
157157
}
158158

159159
// Not pure; perform string interpolation.
160-
for j := range ref.matches {
160+
for j := range ref.Matches {
161161
// The value is invalid if resolution returned [ErrSkipResolution].
162162
// We must skip those and leave the original variable reference in place.
163163
if !resolved[j].IsValid() {
@@ -169,14 +169,14 @@ func (r *resolver) resolveRef(ref ref, seen []string) (dyn.Value, error) {
169169
if !ok {
170170
return dyn.InvalidValue, fmt.Errorf(
171171
"cannot interpolate non-string value: %s",
172-
ref.matches[j][0],
172+
ref.Matches[j][0],
173173
)
174174
}
175175

176-
ref.str = strings.Replace(ref.str, ref.matches[j][0], s, 1)
176+
ref.Str = strings.Replace(ref.Str, ref.Matches[j][0], s, 1)
177177
}
178178

179-
return dyn.NewValue(ref.str, ref.value.Locations()), nil
179+
return dyn.NewValue(ref.Str, ref.Value.Locations()), nil
180180
}
181181

182182
func (r *resolver) resolveKey(key string, seen []string) (dyn.Value, error) {
@@ -204,7 +204,7 @@ func (r *resolver) resolveKey(key string, seen []string) (dyn.Value, error) {
204204
}
205205

206206
// If the returned value is a valid variable reference, resolve it.
207-
ref, ok := newRef(v)
207+
ref, ok := NewRef(v)
208208
if ok {
209209
v, err = r.resolveRef(ref, seen)
210210
}

0 commit comments

Comments
 (0)