From 3bb6a5896b7672ef3ad27f80769f9ca7d366556b Mon Sep 17 00:00:00 2001
From: Zac Clifton <43915749+Cliftonz@users.noreply.github.com>
Date: Wed, 26 Apr 2023 15:41:32 -0400
Subject: [PATCH] Feat: Add strcontains function and documentation (#33069)
* add strcontains function and documentation
---
internal/lang/funcs/descriptions.go | 4 ++
internal/lang/funcs/string.go | 26 ++++++++
internal/lang/funcs/string_test.go | 63 +++++++++++++++++++
internal/lang/functions.go | 1 +
internal/lang/functions_test.go | 11 ++++
website/data/language-nav-data.json | 4 ++
.../docs/language/functions/strcontains.mdx | 25 ++++++++
website/layouts/language.erb | 4 ++
8 files changed, 138 insertions(+)
create mode 100644 website/docs/language/functions/strcontains.mdx
diff --git a/internal/lang/funcs/descriptions.go b/internal/lang/funcs/descriptions.go
index 7d606f2e60ea..8c49f45f4f3d 100644
--- a/internal/lang/funcs/descriptions.go
+++ b/internal/lang/funcs/descriptions.go
@@ -391,6 +391,10 @@ var DescriptionList = map[string]descriptionEntry{
Description: "`startswith` takes two values: a string to check and a prefix string. The function returns true if the string begins with that exact prefix.",
ParamDescription: []string{"", ""},
},
+ "strcontains": {
+ Description: "`strcontains` takes two values: a string to check and an expected substring. The function returns true if the string has the substring contained within it.",
+ ParamDescription: []string{"", ""},
+ },
"strrev": {
Description: "`strrev` reverses the characters in a string. Note that the characters are treated as _Unicode characters_ (in technical terms, Unicode [grapheme cluster boundaries](https://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries) are respected).",
ParamDescription: []string{""},
diff --git a/internal/lang/funcs/string.go b/internal/lang/funcs/string.go
index 9ef709c7fb09..3cc78952dce6 100644
--- a/internal/lang/funcs/string.go
+++ b/internal/lang/funcs/string.go
@@ -103,3 +103,29 @@ var ReplaceFunc = function.New(&function.Spec{
func Replace(str, substr, replace cty.Value) (cty.Value, error) {
return ReplaceFunc.Call([]cty.Value{str, substr, replace})
}
+
+// StrContainsFunc searches a given string for another given substring,
+// if found the function returns true, otherwise returns false.
+var StrContainsFunc = function.New(&function.Spec{
+ Params: []function.Parameter{
+ {
+ Name: "str",
+ Type: cty.String,
+ },
+ {
+ Name: "substr",
+ Type: cty.String,
+ },
+ },
+ Type: function.StaticReturnType(cty.Bool),
+ Impl: func(args []cty.Value, retType cty.Type) (ret cty.Value, err error) {
+ str := args[0].AsString()
+ substr := args[1].AsString()
+
+ if strings.Contains(str, substr) {
+ return cty.True, nil
+ }
+
+ return cty.False, nil
+ },
+})
diff --git a/internal/lang/funcs/string_test.go b/internal/lang/funcs/string_test.go
index 7b44a2762402..71df343634b3 100644
--- a/internal/lang/funcs/string_test.go
+++ b/internal/lang/funcs/string_test.go
@@ -71,3 +71,66 @@ func TestReplace(t *testing.T) {
})
}
}
+
+func TestStrContains(t *testing.T) {
+ tests := []struct {
+ String cty.Value
+ Substr cty.Value
+ Want cty.Value
+ Err bool
+ }{
+ {
+ cty.StringVal("hello"),
+ cty.StringVal("hel"),
+ cty.BoolVal(true),
+ false,
+ },
+ {
+ cty.StringVal("hello"),
+ cty.StringVal("lo"),
+ cty.BoolVal(true),
+ false,
+ },
+ {
+ cty.StringVal("hello1"),
+ cty.StringVal("1"),
+ cty.BoolVal(true),
+ false,
+ },
+ {
+ cty.StringVal("hello1"),
+ cty.StringVal("heo"),
+ cty.BoolVal(false),
+ false,
+ },
+ {
+ cty.StringVal("hello1"),
+ cty.NumberIntVal(1),
+ cty.UnknownVal(cty.Bool),
+ true,
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(fmt.Sprintf("includes(%#v, %#v)", test.String, test.Substr), func(t *testing.T) {
+ got, err := StrContains(test.String, test.Substr)
+
+ if test.Err {
+ if err == nil {
+ t.Fatal("succeeded; want error")
+ }
+ return
+ } else if err != nil {
+ t.Fatalf("unexpected error: %s", err)
+ }
+
+ if !got.RawEquals(test.Want) {
+ t.Errorf("wrong result\ngot: %#v\nwant: %#v", got, test.Want)
+ }
+ })
+ }
+}
+
+func StrContains(str, substr cty.Value) (cty.Value, error) {
+ return StrContainsFunc.Call([]cty.Value{str, substr})
+}
diff --git a/internal/lang/functions.go b/internal/lang/functions.go
index b024e5516481..f27ece88be52 100644
--- a/internal/lang/functions.go
+++ b/internal/lang/functions.go
@@ -117,6 +117,7 @@ func (s *Scope) Functions() map[string]function.Function {
"sort": stdlib.SortFunc,
"split": stdlib.SplitFunc,
"startswith": funcs.StartsWithFunc,
+ "strcontains": funcs.StrContainsFunc,
"strrev": stdlib.ReverseFunc,
"substr": stdlib.SubstrFunc,
"sum": funcs.SumFunc,
diff --git a/internal/lang/functions_test.go b/internal/lang/functions_test.go
index 32a9762d3998..ce1d9586d452 100644
--- a/internal/lang/functions_test.go
+++ b/internal/lang/functions_test.go
@@ -906,6 +906,17 @@ func TestFunctions(t *testing.T) {
},
},
+ "strcontains": {
+ {
+ `strcontains("hello", "llo")`,
+ cty.BoolVal(true),
+ },
+ {
+ `strcontains("hello", "a")`,
+ cty.BoolVal(false),
+ },
+ },
+
"strrev": {
{
`strrev("hello world")`,
diff --git a/website/data/language-nav-data.json b/website/data/language-nav-data.json
index e489f8e71cd4..2b8226b133d6 100644
--- a/website/data/language-nav-data.json
+++ b/website/data/language-nav-data.json
@@ -337,6 +337,10 @@
"title": "startswith
",
"href": "/language/functions/startswith"
},
+ {
+ "title": "strcontains
",
+ "href": "/language/functions/strcontains"
+ },
{
"title": "strrev
",
"href": "/language/functions/strrev"
diff --git a/website/docs/language/functions/strcontains.mdx b/website/docs/language/functions/strcontains.mdx
new file mode 100644
index 000000000000..6e684a6f6aa1
--- /dev/null
+++ b/website/docs/language/functions/strcontains.mdx
@@ -0,0 +1,25 @@
+---
+page_title: strcontains - Functions - Configuration Language
+description: |-
+ The strcontains function checks whether a given string can be found within another string.
+---
+
+# `strcontains` Function
+
+`strcontains` function checks whether a substring is within another string.
+
+```hcl
+strcontains(string, substr)
+```
+
+## Examples
+
+```
+> strcontains("hello world", "wor")
+true
+```
+
+```
+> strcontains("hello world", "wod")
+false
+```
\ No newline at end of file
diff --git a/website/layouts/language.erb b/website/layouts/language.erb
index 4aa951904a21..c93f429f492f 100644
--- a/website/layouts/language.erb
+++ b/website/layouts/language.erb
@@ -418,6 +418,10 @@
startswith
+