Skip to content

Commit

Permalink
Update variable regex to support hyphens (#503)
Browse files Browse the repository at this point in the history
## Changes

Modified interpolation logic to use:
`\$\{([a-zA-Z]+([-_]*[a-zA-Z0-9]+)*(\.[a-zA-Z]+([-_]*[a-zA-Z0-9]+)*)*)\}`

**Edit**: Suggested by @pietern
`\$\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\}`
to be more selective and not allow consequent hyphens or underscores to
make the keys more readable.

Explanation:
1. All interpolation starts with `${` and ends with `}`
2. All interpolated locations are split by by `.`
3. All sections are expected to start with a alphabet `[a-zA-Z]`; no
numbers, hyphens or underscores.
4. All sections are expected to end with an alphanumeric `[a-zA-Z0-9]`
no hyphens or underscores

This change allows the current interpolation to be more permissive.

**Note** it does break backwards compatibility because `[a-zA-Z] !=
[\w]`. `\w` includes alphanumeric and underscores. `\w = [a-zA-Z0-9_]`

## Tests
There are two tests with examples of valid and invalid interpolation and
a test to validate expansion.
  • Loading branch information
stikkireddy authored Jun 23, 2023
1 parent ae13135 commit 3c1e69a
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 1 deletion.
3 changes: 2 additions & 1 deletion bundle/config/interpolation/interpolation.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import (

const Delimiter = "."

var re = regexp.MustCompile(`\$\{(\w+(\.\w+)*)\}`)
// must start with alphabet, support hyphens and underscores in middle but must end with character
var re = regexp.MustCompile(`\$\{([a-zA-Z]+([-_]?[a-zA-Z0-9]+)*(\.[a-zA-Z]+([-_]?[a-zA-Z0-9]+)*)*)\}`)

type stringField struct {
path string
Expand Down
55 changes: 55 additions & 0 deletions bundle/config/interpolation/interpolation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,61 @@ func TestInterpolationVariables(t *testing.T) {
assert.Equal(t, "a", f.C)
}

func TestInterpolationVariablesSpecialChars(t *testing.T) {
type bar struct {
A string `json:"a-b"`
B string `json:"b_c"`
C string `json:"c-_a"`
}
f := bar{
A: "a",
B: "${a-b}",
C: "${a-b}",
}

err := expand(&f)
require.NoError(t, err)

assert.Equal(t, "a", f.A)
assert.Equal(t, "a", f.B)
assert.Equal(t, "a", f.C)
}

func TestInterpolationValidMatches(t *testing.T) {
expectedMatches := map[string]string{
"${hello_world.world_world}": "hello_world.world_world",
"${helloworld.world-world}": "helloworld.world-world",
"${hello-world.world-world}": "hello-world.world-world",
}
for interpolationStr, expectedMatch := range expectedMatches {
match := re.FindStringSubmatch(interpolationStr)
assert.True(t, len(match) > 0,
"Failed to match %s and find %s", interpolationStr, expectedMatch)
assert.Equal(t, expectedMatch, match[1],
"Failed to match the exact pattern %s and find %s", interpolationStr, expectedMatch)
}
}

func TestInterpolationInvalidMatches(t *testing.T) {
invalidMatches := []string{
"${hello_world-.world_world}", // the first segment ending must not end with hyphen (-)
"${hello_world-_.world_world}", // the first segment ending must not end with underscore (_)
"${helloworld.world-world-}", // second segment must not end with hyphen (-)
"${helloworld-.world-world}", // first segment must not end with hyphen (-)
"${helloworld.-world-world}", // second segment must not start with hyphen (-)
"${-hello-world.-world-world-}", // must not start or end with hyphen (-)
"${_-_._-_.id}", // cannot use _- in sequence
"${0helloworld.world-world}", // interpolated first section shouldn't start with number
"${helloworld.9world-world}", // interpolated second section shouldn't start with number
"${a-a.a-_a-a.id}", // fails because of -_ in the second segment
"${a-a.a--a-a.id}", // fails because of -- in the second segment
}
for _, invalidMatch := range invalidMatches {
match := re.FindStringSubmatch(invalidMatch)
assert.True(t, len(match) == 0, "Should be invalid interpolation: %s", invalidMatch)
}
}

func TestInterpolationWithPointers(t *testing.T) {
fd := "${a}"
f := foo{
Expand Down

0 comments on commit 3c1e69a

Please sign in to comment.