terraform-provider-multireplaceを作った(が、すでにあった)

terraformのjsonencode()には<, >, &\u003c, \u003e, \u0026 に変換するよく知られた仕様がある。

developer.hashicorp.com

When encoding strings, this function escapes some characters using Unicode escape sequences: replacing <, >, &, U+2028, and U+2029 with \u003c, \u003e, \u0026, \u2028, and \u2029. This is to preserve compatibility with Terraform 0.11 behavior.

github.com

replace()を使うのが今のところの回避策ではあるが、複数の文字列を置換するのがめんどいのでmultireplace() jsonunescape()というユーザー定義関数を作った。

github.com

output "london_bridge" {
  value = provider::multireplace::multireplace(
    "London Bridge Is Falling Down, Falling down, falling down",
    { Falling = "Winding", falling = "jumping" }
  )
  #=> "London Bridge Is Winding Down, Winding down, jumping down"

  # value = provider::multireplace::multireplace(
  #   "London Bridge Is Falling Down, Falling down, falling down",
  #     { Falling = "Winding" },
  #     { falling = "jumping" }
  # )
}
locals {
  # see https://developer.hashicorp.com/terraform/language/functions/jsonencode
  jsonencode_html = jsonencode({
    link = "<a href=\"https://example.com?foo=bar&zoo=baz\">Open</a>"
  })

  jsonunescape_html = provider::multireplace::jsonunescape(local.jsonencode_html)
}

output "html" {
  value = <<-EOT
    ${local.jsonencode_html}
    ---
    ${local.jsonunescape_html}
  EOT
  #=> <<-EOT
  #       {"link":"\u003ca href=\"https://example.com?foo=bar\u0026zoo=baz\"\u003eOpen\u003c/a\u003e"}
  #       ---
  #       {"link":"<a href=\"https://example.com?foo=bar&zoo=baz\">Open</a>"}
  #   EOT
}

その後、よく調べたらmultireplace()については既存の実装があった。

github.com

locals {
  # 実際の関数呼び出しは `provider::string-functions::multi_replace(...)`
  replaced = multi_replace("a,b,c,d,e", {
    "," = "|",
    "a" = "z",
  })
}

output "replaced" {
  value = local.replaced
}

# replaced = "z|b|c|d|e"

こちらの方はmulti_replace()だけではなく、Case conversionやEscapingなど文字列まわりの便利関数が一通りそろっている。


jsonencode()に特化している訳ではないので、自作のterraform-provider-multireplaceプロバイダは使っていくと思うが、terraform-provider-string-functionsもなかなか便利そうなので今後使っていきたい。