in pkg/internal/expression/interpolation.go [17:93]
func interpolateString(obj *InterpolationContext, value string) (*context.Value, error) {
output := []*structpb.Value{}
depth := 0
prev_idx := 0
open_idx := 0
sensitive := false
sensitiveReasons := make([]string, 0)
for _, loc := range interpolateRegex.FindAllStringIndex(value, -1) {
if depth == 0 && prev_idx != loc[0] {
// add prefix to output
output = append(output, structpb.NewStringValue(value[prev_idx:loc[0]]))
}
prev_idx = loc[1]
switch value[loc[0]:loc[1]] {
case InterpolateOpen:
depth += 1
if depth == 1 {
open_idx = loc[1]
}
case InterpolateClose:
depth -= 1
insideString := value[open_idx:loc[0]]
if depth < 0 {
return nil, fmt.Errorf("The %q has extra '}}'", insideString)
} else if depth > 0 {
break
}
insideValue, err := Evaluate(obj, insideString)
if err != nil {
return nil, err
}
if insideValue.Sensitive {
sensitive = true
sensitiveReasons = append(sensitiveReasons, insideValue.SensitiveReason)
}
output = append(output, insideValue.Value)
default:
}
}
if depth > 0 {
return nil, fmt.Errorf("The %q is not closed: ${{ ... }}", value[open_idx:])
}
// add suffix to output
if prev_idx != len(value) {
output = append(output, structpb.NewStringValue(value[prev_idx:]))
}
// retain type if this is single item, otherwise convert to string
if len(output) == 1 {
return context.NewValue(output[0], sensitive, sensitiveReasons...), nil
}
// concat all items
res := ""
for _, o := range output {
str, err := ValueToString(o)
if err != nil {
return nil, err
}
res += str
}
return context.NewStringValue(res, sensitive, sensitiveReasons...), nil
}