From c73c0ad63c094644cd9d9d584d0802cf6c9d0b7b Mon Sep 17 00:00:00 2001 From: Joshua Barton Date: Thu, 9 Jun 2022 16:55:38 -0500 Subject: [PATCH 1/5] feat: add startswith and endswith funcs --- internal/lang/funcs/string.go | 52 +++++++++++++++++++++++++++++++++ internal/lang/functions.go | 2 ++ internal/lang/functions_test.go | 22 ++++++++++++++ 3 files changed, 76 insertions(+) diff --git a/internal/lang/funcs/string.go b/internal/lang/funcs/string.go index ab6da72778ec..9ef709c7fb09 100644 --- a/internal/lang/funcs/string.go +++ b/internal/lang/funcs/string.go @@ -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{ diff --git a/internal/lang/functions.go b/internal/lang/functions.go index 1b3f88ce0476..ee520965caeb 100644 --- a/internal/lang/functions.go +++ b/internal/lang/functions.go @@ -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), @@ -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, diff --git a/internal/lang/functions_test.go b/internal/lang/functions_test.go index ea2091eb97fa..b18493c8cdc6 100644 --- a/internal/lang/functions_test.go +++ b/internal/lang/functions_test.go @@ -314,6 +314,17 @@ func TestFunctions(t *testing.T) { }, }, + "endswith": { + { + `endswith("hello world", "world")`, + cty.True, + }, + { + `endswith("hello world", "hello")`, + cty.False, + }, + }, + "file": { { `file("hello.txt")`, @@ -816,6 +827,17 @@ func TestFunctions(t *testing.T) { }, }, + "startswith": { + { + `startswith("hello world", "hello")`, + cty.True, + }, + { + `startswith("hello world", "world")`, + cty.False, + }, + }, + "strrev": { { `strrev("hello world")`, From fd3798b276b237e98218fcb20c9c78e92b3397ff Mon Sep 17 00:00:00 2001 From: Joshua Barton Date: Thu, 30 Jun 2022 17:57:31 -0500 Subject: [PATCH 2/5] tests: add test cases around empty values --- internal/lang/functions_test.go | 60 +++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/internal/lang/functions_test.go b/internal/lang/functions_test.go index b18493c8cdc6..f2a6f738c468 100644 --- a/internal/lang/functions_test.go +++ b/internal/lang/functions_test.go @@ -323,6 +323,36 @@ func TestFunctions(t *testing.T) { `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": { @@ -836,6 +866,36 @@ func TestFunctions(t *testing.T) { `startswith("hello world", "world")`, cty.False, }, + { + `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": { From 2278d308577b6003dced2ce4f610c0c04fc0d79c Mon Sep 17 00:00:00 2001 From: Joshua Barton Date: Thu, 30 Jun 2022 18:12:44 -0500 Subject: [PATCH 3/5] docs: add documentation for starts and endswith --- website/data/language-nav-data.json | 10 +++++++ website/docs/language/functions/endswith.mdx | 30 +++++++++++++++++++ .../docs/language/functions/startswith.mdx | 30 +++++++++++++++++++ website/layouts/language.erb | 8 +++++ 4 files changed, 78 insertions(+) create mode 100644 website/docs/language/functions/endswith.mdx create mode 100644 website/docs/language/functions/startswith.mdx diff --git a/website/data/language-nav-data.json b/website/data/language-nav-data.json index a0ec64131e4e..60a649ada4ae 100644 --- a/website/data/language-nav-data.json +++ b/website/data/language-nav-data.json @@ -319,6 +319,10 @@ "title": "chomp", "href": "/language/functions/chomp" }, + { + "title": "endswith", + "href": "/language/functions/endswith" + }, { "title": "format", "href": "/language/functions/format" @@ -352,6 +356,10 @@ "title": "split", "href": "/language/functions/split" }, + { + "title": "startswith", + "href": "/language/functions/startswith" + }, { "title": "strrev", "href": "/language/functions/strrev" @@ -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 }, { @@ -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 }, diff --git a/website/docs/language/functions/endswith.mdx b/website/docs/language/functions/endswith.mdx new file mode 100644 index 000000000000..8599f3582b7a --- /dev/null +++ b/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. +--- + +# `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. + +```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 diff --git a/website/docs/language/functions/startswith.mdx b/website/docs/language/functions/startswith.mdx new file mode 100644 index 000000000000..02295beade3c --- /dev/null +++ b/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. +--- + +# `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. + +```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 \ No newline at end of file diff --git a/website/layouts/language.erb b/website/layouts/language.erb index 7f7e55e7f3df..f2bf83dede52 100644 --- a/website/layouts/language.erb +++ b/website/layouts/language.erb @@ -370,6 +370,10 @@ chomp +
  • + endswith +
  • +
  • format
  • @@ -406,6 +410,10 @@ split +
  • + startswith +
  • +
  • strrev
  • From 0dfcbe6d0c4725fd48af86897e5d2381f558f851 Mon Sep 17 00:00:00 2001 From: Joshua Barton Date: Thu, 14 Jul 2022 11:06:35 -0500 Subject: [PATCH 4/5] docs: Add recommended language changes Co-authored-by: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> --- website/docs/language/functions/endswith.mdx | 9 +++------ website/docs/language/functions/startswith.mdx | 9 +++------ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/website/docs/language/functions/endswith.mdx b/website/docs/language/functions/endswith.mdx index 8599f3582b7a..a150290804c2 100644 --- a/website/docs/language/functions/endswith.mdx +++ b/website/docs/language/functions/endswith.mdx @@ -1,14 +1,12 @@ --- 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. + The endswith function takes two values: a string to check and a suffix string. It returns true if the first string ends with that exact suffix value. --- # `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. +`endswith` takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix value. ```hcl endswith(string, suffix) @@ -26,5 +24,4 @@ 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 +- [`startswith`](/language/functions/startswith) takes two values: a string to check and a prefix string. The function returns true if the string begins with that exact prefix. diff --git a/website/docs/language/functions/startswith.mdx b/website/docs/language/functions/startswith.mdx index 02295beade3c..4b9392a0b0a8 100644 --- a/website/docs/language/functions/startswith.mdx +++ b/website/docs/language/functions/startswith.mdx @@ -1,14 +1,12 @@ --- 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. + The startswith function takes two values: a string to check and a prefix string. It returns true if the string begins with that exact prefix. --- # `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. +`startswith` takes two values: a string to check and a prefix string. The function returns true if the string begins with that exact prefix. ```hcl startswith(string, prefix) @@ -26,5 +24,4 @@ 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 \ No newline at end of file +- [`endswith`](/language/functions/endswith) takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix value. \ No newline at end of file From 719089850165a1f1c6e29a23d69482c8c03e292e Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Thu, 14 Jul 2022 13:03:53 -0400 Subject: [PATCH 5/5] Apply suggestions from code review Co-authored-by: Laura Pacilio <83350965+laurapacilio@users.noreply.github.com> --- website/docs/language/functions/endswith.mdx | 4 ++-- website/docs/language/functions/startswith.mdx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/language/functions/endswith.mdx b/website/docs/language/functions/endswith.mdx index a150290804c2..d96cc88aad8c 100644 --- a/website/docs/language/functions/endswith.mdx +++ b/website/docs/language/functions/endswith.mdx @@ -1,12 +1,12 @@ --- page_title: endswith - Functions - Configuration Language description: |- - The endswith function takes two values: a string to check and a suffix string. It returns true if the first string ends with that exact suffix value. + The endswith function takes two values: a string to check and a suffix string. It returns true if the first string ends with that exact suffix. --- # `endswith` Function -`endswith` takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix value. +`endswith` takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix. ```hcl endswith(string, suffix) diff --git a/website/docs/language/functions/startswith.mdx b/website/docs/language/functions/startswith.mdx index 4b9392a0b0a8..d49f7aa0ba13 100644 --- a/website/docs/language/functions/startswith.mdx +++ b/website/docs/language/functions/startswith.mdx @@ -24,4 +24,4 @@ false ## Related Functions -- [`endswith`](/language/functions/endswith) takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix value. \ No newline at end of file +- [`endswith`](/language/functions/endswith) takes two values: a string to check and a suffix string. The function returns true if the first string ends with that exact suffix. \ No newline at end of file