Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add startswith and endswith funcs #31220

Merged
merged 5 commits into from Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
52 changes: 52 additions & 0 deletions internal/lang/funcs/string.go
Expand Up @@ -8,6 +8,58 @@ import (
"github.com/zclconf/go-cty/cty/function"
)

// StartsWithFunc constructs a function that checks if a string starts with
// a specific prefix using strings.HasPrefix
var StartsWithFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "str",
Type: cty.String,
},
{
Name: "prefix",
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.Bool),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
str := args[0].AsString()
prefix := args[1].AsString()

if strings.HasPrefix(str, prefix) {
return cty.True, nil
}

return cty.False, nil
},
})

// EndsWithFunc constructs a function that checks if a string ends with
// a specific suffix using strings.HasSuffix
var EndsWithFunc = function.New(&function.Spec{
Params: []function.Parameter{
{
Name: "str",
Type: cty.String,
},
{
Name: "suffix",
Type: cty.String,
},
},
Type: function.StaticReturnType(cty.Bool),
Impl: func(args []cty.Value, retType cty.Type) (cty.Value, error) {
str := args[0].AsString()
suffix := args[1].AsString()

if strings.HasSuffix(str, suffix) {
return cty.True, nil
}

return cty.False, nil
},
})

// ReplaceFunc constructs a function that searches a given string for another
// given substring, and replaces each occurence with a given replacement string.
var ReplaceFunc = function.New(&function.Spec{
Expand Down
2 changes: 2 additions & 0 deletions internal/lang/functions.go
Expand Up @@ -59,6 +59,7 @@ func (s *Scope) Functions() map[string]function.Function {
"dirname": funcs.DirnameFunc,
"distinct": stdlib.DistinctFunc,
"element": stdlib.ElementFunc,
"endswith": funcs.EndsWithFunc,
"chunklist": stdlib.ChunklistFunc,
"file": funcs.MakeFileFunc(s.BaseDir, false),
"fileexists": funcs.MakeFileExistsFunc(s.BaseDir),
Expand Down Expand Up @@ -115,6 +116,7 @@ func (s *Scope) Functions() map[string]function.Function {
"slice": stdlib.SliceFunc,
"sort": stdlib.SortFunc,
"split": stdlib.SplitFunc,
"startswith": funcs.StartsWithFunc,
"strrev": stdlib.ReverseFunc,
"substr": stdlib.SubstrFunc,
"sum": funcs.SumFunc,
Expand Down
82 changes: 82 additions & 0 deletions internal/lang/functions_test.go
Expand Up @@ -314,6 +314,47 @@ func TestFunctions(t *testing.T) {
},
},

"endswith": {
{
`endswith("hello world", "world")`,
cty.True,
},
{
`endswith("hello world", "hello")`,
cty.False,
},
{
`endswith("hello world", "")`,
cty.True,
// Completely empty suffix value ( "" )
// will always evaluate to true for all strings.
},
{
`endswith("hello world", " ")`,
cty.False,
},
{
`endswith("", "")`,
cty.True,
},
{
`endswith("", " ")`,
cty.False,
},
{
`endswith(" ", "")`,
cty.True,
},
{
`endswith("", "hello")`,
cty.False,
},
{
`endswith(" ", "hello")`,
cty.False,
},
},

"file": {
{
`file("hello.txt")`,
Expand Down Expand Up @@ -816,6 +857,47 @@ func TestFunctions(t *testing.T) {
},
},

"startswith": {
{
`startswith("hello world", "hello")`,
cty.True,
},
{
`startswith("hello world", "world")`,
cty.False,
},
alisdair marked this conversation as resolved.
Show resolved Hide resolved
{
`startswith("hello world", "")`,
cty.True,
// Completely empty prefix value ( "" )
// will always evaluate to true for all strings.
},
{
`startswith("hello world", " ")`,
cty.False,
},
{
`startswith("", "")`,
cty.True,
},
{
`startswith("", " ")`,
cty.False,
},
{
`startswith(" ", "")`,
cty.True,
},
{
`startswith("", "hello")`,
cty.False,
},
{
`startswith(" ", "hello")`,
cty.False,
},
},

"strrev": {
{
`strrev("hello world")`,
Expand Down
10 changes: 10 additions & 0 deletions website/data/language-nav-data.json
Expand Up @@ -319,6 +319,10 @@
"title": "<code>chomp</code>",
"href": "/language/functions/chomp"
},
{
"title": "<code>endswith</code>",
"href": "/language/functions/endswith"
},
{
"title": "<code>format</code>",
"href": "/language/functions/format"
Expand Down Expand Up @@ -352,6 +356,10 @@
"title": "<code>split</code>",
"href": "/language/functions/split"
},
{
"title": "<code>startswith</code>",
"href": "/language/functions/startswith"
},
{
"title": "<code>strrev</code>",
"href": "/language/functions/strrev"
Expand Down Expand Up @@ -776,6 +784,7 @@
{ "title": "dirname", "path": "functions/dirname", "hidden": true },
{ "title": "distinct", "path": "functions/distinct", "hidden": true },
{ "title": "element", "path": "functions/element", "hidden": true },
{ "title": "endswith", "path": "functions/endswith", "hidden": true },
{ "title": "file", "path": "functions/file", "hidden": true },
{ "title": "filebase64", "path": "functions/filebase64", "hidden": true },
{
Expand Down Expand Up @@ -851,6 +860,7 @@
{ "title": "slice", "path": "functions/slice", "hidden": true },
{ "title": "sort", "path": "functions/sort", "hidden": true },
{ "title": "split", "path": "functions/split", "hidden": true },
{ "title": "startswith", "path": "functions/startswith", "hidden": true },
{ "title": "strrev", "path": "functions/strrev", "hidden": true },
{ "title": "substr", "path": "functions/substr", "hidden": true },
{ "title": "sum", "path": "functions/sum", "hidden": true },
Expand Down
30 changes: 30 additions & 0 deletions website/docs/language/functions/endswith.mdx
@@ -0,0 +1,30 @@
---
page_title: endswith - Functions - Configuration Language
description: |-
The endswith function takes a given string and a given suffix value,
and returns true if the first given string contains the given value at its end.
FooBartn marked this conversation as resolved.
Show resolved Hide resolved
---

# `endswith` Function

`endswith` takes a given string and a given suffix value,
and returns true if the first given string contains the given value at its end.

FooBartn marked this conversation as resolved.
Show resolved Hide resolved
```hcl
endswith(string, suffix)
```

## Examples

```
> endswith("hello world", "world")
true

> endswith("hello world", "hello")
false
```

## Related Functions

- [`startswith`](/language/functions/startswith) takes a given string and a given prefix value,
and returns true if the first given string contains the given value at its beginning
FooBartn marked this conversation as resolved.
Show resolved Hide resolved
30 changes: 30 additions & 0 deletions website/docs/language/functions/startswith.mdx
@@ -0,0 +1,30 @@
---
page_title: startsswith - Functions - Configuration Language
description: |-
The startswith function takes a given string and a given prefix value,
and returns true if the first given string contains the given value at its beginning.
FooBartn marked this conversation as resolved.
Show resolved Hide resolved
---

# `startswith` Function

`startswith` takes a given string and a given prefix value,
and returns true if the first given string contains the given value at its beginning.
FooBartn marked this conversation as resolved.
Show resolved Hide resolved

```hcl
startswith(string, prefix)
```

## Examples

```
> startswith("hello world", "hello")
true

> startswith("hello world", "world")
false
```

## Related Functions

- [`endswith`](/language/functions/endswith) takes a given string and a given suffix value,
and returns true if the first given string contains the given value at its end
FooBartn marked this conversation as resolved.
Show resolved Hide resolved
8 changes: 8 additions & 0 deletions website/layouts/language.erb
Expand Up @@ -370,6 +370,10 @@
<a href="/docs/language/functions/chomp.html">chomp</a>
</li>

<li>
<a href="/docs/language/functions/endswith.html">endswith</a>
</li>

<li>
<a href="/docs/language/functions/format.html">format</a>
</li>
Expand Down Expand Up @@ -406,6 +410,10 @@
<a href="/docs/language/functions/split.html">split</a>
</li>

<li>
<a href="/docs/language/functions/startswith.html">startswith</a>
</li>

<li>
<a href="/docs/language/functions/strrev.html">strrev</a>
</li>
Expand Down