func interpolateString()

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
}