smartconfig/interpolate.go
2025-07-20 12:12:14 +02:00

102 lines
2.1 KiB
Go

package smartconfig
import "strings"
// findInterpolations finds all ${...} patterns in the string, handling nested cases
func findInterpolations(s string) []struct{ start, end int } {
var results []struct{ start, end int }
for i := 0; i < len(s); i++ {
if i+2 < len(s) && s[i:i+2] == "${" {
// Found start of interpolation
start := i
braceCount := 1
j := i + 2
// Find matching closing brace
for j < len(s) && braceCount > 0 {
if j+2 <= len(s) && s[j:j+2] == "${" {
braceCount++
j += 2
} else if s[j] == '}' {
braceCount--
j++
} else {
j++
}
}
if braceCount == 0 {
results = append(results, struct{ start, end int }{start, j})
i = j - 1 // Skip past this interpolation
}
}
}
return results
}
// interpolate handles nested interpolations properly
func (c *Config) interpolate(content string, depth int) (string, error) {
if depth >= maxRecursionDepth {
return content, nil
}
result := content
changed := true
for changed && depth < maxRecursionDepth {
changed = false
positions := findInterpolations(result)
// Process from end to beginning to maintain string positions
for i := len(positions) - 1; i >= 0; i-- {
pos := positions[i]
fullMatch := result[pos.start:pos.end]
// Extract the content inside ${}
inner := fullMatch[2 : len(fullMatch)-1]
// Find the resolver and value
colonIdx := strings.Index(inner, ":")
if colonIdx == -1 {
continue
}
resolverName := inner[:colonIdx]
value := inner[colonIdx+1:]
// Check if value contains nested interpolations
if strings.Contains(value, "${") {
// Recursively interpolate the value first
interpolatedValue, err := c.interpolate(value, depth+1)
if err != nil {
continue
}
value = interpolatedValue
}
// Resolve the value
resolver, ok := c.resolvers[resolverName]
if !ok {
continue
}
resolved, err := resolver.Resolve(value)
if err != nil {
continue
}
// Replace the match
result = result[:pos.start] + resolved + result[pos.end:]
changed = true
}
if changed {
depth++
}
}
return result, nil
}