Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions envsubst/eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ func TestExpand(t *testing.T) {
input: "${stringZ/#abc/XYZ}",
output: "XYZABC123ABCabc",
},
// replace prefix with empty pattern (prepend)
{
params: map[string]string{"stringZ": "somevalue"},
input: "${stringZ/#/prefix-}",
output: "prefix-somevalue",
},
// replace suffix with empty pattern (append)
{
params: map[string]string{"stringZ": "somevalue"},
input: "${stringZ/%/-suffix}",
output: "somevalue-suffix",
},
// replace all
{
params: map[string]string{"stringZ": "abcABC123ABCabc"},
Expand Down
15 changes: 11 additions & 4 deletions envsubst/parse/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,18 @@ func (t *Tree) parseReplaceFunc(name string) (Node, error) {

// scan arg[1]
{
param, err := t.parseParam(acceptNotSlash, scanIdent|scanEscape)
if err != nil {
return nil, err
// An empty pattern (e.g. ${param/#/string}) means the next rune is the
// delimiter, so there is nothing to scan. Record an empty pattern node
// to keep the two-argument shape the eval side expects.
if t.scanner.peek() == '/' {
node.Args = append(node.Args, newTextNode(""))
} else {
param, err := t.parseParam(acceptNotSlash, scanIdent|scanEscape)
if err != nil {
return nil, err
}
node.Args = append(node.Args, param)
}
node.Args = append(node.Args, param)
}

// expect delimiter
Expand Down
22 changes: 22 additions & 0 deletions envsubst/parse/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,28 @@ var tests = []struct {
},
},
},
{
Text: "${string/#/replacement}",
Node: &FuncNode{
Param: "string",
Name: "/#",
Args: []Node{
&TextNode{Value: ""},
&TextNode{Value: "replacement"},
},
},
},
{
Text: "${string/%/replacement}",
Node: &FuncNode{
Param: "string",
Name: "/%",
Args: []Node{
&TextNode{Value: ""},
&TextNode{Value: "replacement"},
},
},
},

//
// default value functions
Expand Down