diff --git a/README.md b/README.md index dc7e7422..12cebd2e 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ To see all the available options, run `tox -l`. ## Releasing -To create a new releaes go to Releases page, press 'Draft a new release', create a tag +To create a new release go to Releases page, press 'Draft a new release', create a tag with a version you want to be released, fill the release notes and press 'Publish release'. Github actions will take care of publishing it to PyPi. @@ -84,3 +84,23 @@ We welcome pull requests! For your pull request to be accepted smoothly, we sugg - Create a pull request. Explain why you want to make the change and what it’s for. We’ll try to answer any PR’s promptly. + +## Limitations + +### Error parsing string interpolations nested more than 2 times + +- Parsing following example is expected to throw out an exception and fail: + ```terraform + locals { + foo = "foo" + name = "prefix1-${"prefix2-${"${local.foo}-bar"}"}" //should interpolate into "prefix1-prefix2-foo-bar" but fails + } + ``` + We recommend working around this by modifying the configuration in the following manner: + ```terraform + locals { + foo = "foo" + foo_bar = "${local.foo}-bar" + name = "prefix1-${"prefix2-${local.foo_bar}"}" //interpolates into "prefix1-prefix2-foo-bar" + } + ``` diff --git a/hcl2/hcl2.lark b/hcl2/hcl2.lark index 06cccfd1..0f5437fc 100644 --- a/hcl2/hcl2.lark +++ b/hcl2/hcl2.lark @@ -1,7 +1,7 @@ start : body body : (new_line_or_comment? (attribute | block))* new_line_or_comment? attribute : identifier EQ expression -block : identifier (identifier | STRING_LIT | string_with_interpolation)* new_line_or_comment? "{" body "}" +block : identifier (identifier | STRING_LIT)* new_line_or_comment? "{" body "}" new_line_or_comment: ( NL_OR_COMMENT )+ NL_OR_COMMENT: /\n[ \t]*/ | /#.*\n/ | /\/\/.*\n/ | /\/\*(.|\n)*?(\*\/)/ @@ -42,7 +42,6 @@ expr_term : LPAR new_line_or_comment? expression new_line_or_comment? RPAR | float_lit | int_lit | STRING_LIT - | string_with_interpolation | tuple | object | function_call @@ -57,10 +56,11 @@ expr_term : LPAR new_line_or_comment? expression new_line_or_comment? RPAR | for_tuple_expr | for_object_expr -STRING_LIT : "\"" STRING_CHARS? "\"" -STRING_CHARS : /(?:(?!\${)([^"\\]|\\.))+/ // any character except '"' -string_with_interpolation: "\"" (STRING_CHARS)* interpolation_maybe_nested (STRING_CHARS | interpolation_maybe_nested)* "\"" -interpolation_maybe_nested: "${" expression "}" +STRING_LIT : "\"" (STRING_CHARS | INTERPOLATION)* "\"" +STRING_CHARS : /(?:(?!\${)([^"\\]|\\.))+/+ // any character except '"" unless inside a interpolation string +NESTED_INTERPOLATION : "${" /[^}]+/ "}" +INTERPOLATION : "${" (/(?:(?!\${)([^}]))+/ | NESTED_INTERPOLATION)+ "}" + int_lit : NEGATIVE_DECIMAL? DECIMAL+ | NEGATIVE_DECIMAL+ !float_lit: (NEGATIVE_DECIMAL? DECIMAL+ | NEGATIVE_DECIMAL+) "." DECIMAL+ (EXP_MARK)? diff --git a/test/helpers/terraform-config-json/locals_embedded_interpolation.json b/test/helpers/terraform-config-json/locals_embedded_interpolation.json deleted file mode 100644 index 8732531f..00000000 --- a/test/helpers/terraform-config-json/locals_embedded_interpolation.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "locals": [ - { - "embedded_interpolation": "(long substring without interpolation); ${module.special_constants.aws_accounts[\"aaa-${local.foo}-${local.bar}\"]}/us-west-2/key_foo" - } - ] -} diff --git a/test/helpers/terraform-config-json/multi_level_interpolation.json b/test/helpers/terraform-config-json/multi_level_interpolation.json deleted file mode 100644 index ab2af720..00000000 --- a/test/helpers/terraform-config-json/multi_level_interpolation.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "block": [ - { - "a": "${\"${\"${\"a\"}\"}\"}" - }, - { - "b": "${var.b}" - } - ] -} diff --git a/test/helpers/terraform-config-json/string_interpolations.json b/test/helpers/terraform-config-json/string_interpolations.json new file mode 100644 index 00000000..76bd5454 --- /dev/null +++ b/test/helpers/terraform-config-json/string_interpolations.json @@ -0,0 +1 @@ +{"locals": [{"simple_interpolation": "prefix:${var.foo}-suffix", "embedded_interpolation": "(long substring without interpolation); ${module.special_constants.aws_accounts[\"aaa-${local.foo}-${local.bar}\"]}/us-west-2/key_foo", "escaped_interpolation": "prefix:$${aws:username}-suffix"}]} diff --git a/test/helpers/terraform-config/multi_level_interpolation.tf b/test/helpers/terraform-config/multi_level_interpolation.tf deleted file mode 100644 index ab42c736..00000000 --- a/test/helpers/terraform-config/multi_level_interpolation.tf +++ /dev/null @@ -1,7 +0,0 @@ -block { - a = "${"${"${"a"}"}"}" -} - -block { - b = "${var.b}" -} diff --git a/test/helpers/terraform-config/locals_embedded_interpolation.tf b/test/helpers/terraform-config/string_interpolations.tf similarity index 60% rename from test/helpers/terraform-config/locals_embedded_interpolation.tf rename to test/helpers/terraform-config/string_interpolations.tf index 2a89f595..eed3be33 100644 --- a/test/helpers/terraform-config/locals_embedded_interpolation.tf +++ b/test/helpers/terraform-config/string_interpolations.tf @@ -1,3 +1,5 @@ locals { + simple_interpolation = "prefix:${var.foo}-suffix" embedded_interpolation = "(long substring without interpolation); ${module.special_constants.aws_accounts["aaa-${local.foo}-${local.bar}"]}/us-west-2/key_foo" + escaped_interpolation = "prefix:$${aws:username}-suffix" } diff --git a/test/unit/test_builder.py b/test/unit/test_builder.py index 56d7e308..ec9d7fac 100644 --- a/test/unit/test_builder.py +++ b/test/unit/test_builder.py @@ -64,14 +64,16 @@ def test_locals_embedded_function_tf(self): def test_locals_embedded_interpolation_tf(self): builder = hcl2.Builder() - embedded_interpolation = ( - "(long substring without interpolation); ${module.special_constants.aws_accounts" - '["aaa-${local.foo}-${local.bar}"]}/us-west-2/key_foo' - ) + attributes = { + "simple_interpolation": "prefix:${var.foo}-suffix", + "embedded_interpolation": "(long substring without interpolation); " + '${module.special_constants.aws_accounts["aaa-${local.foo}-${local.bar}"]}/us-west-2/key_foo', + "escaped_interpolation": "prefix:$${aws:username}-suffix", + } - builder.block("locals", embedded_interpolation=embedded_interpolation) + builder.block("locals", **attributes) - self.compare_filenames(builder, "locals_embedded_interpolation.tf") + self.compare_filenames(builder, "string_interpolations.tf") def test_provider_function_tf(self): builder = hcl2.Builder()