Remove hanging indent on HEREDOCs with <<- prefix
This commit adds support for removing a hanging indent from HEREDOC token contents if the marker is prefixed with <<-. For example, given the HCL definition: my_long_var_name = <<-EOF { "key": "value" } EOF The value of the HEREDOC will be: { "key": "value" } This is useful for use cases where indentation or leading whitespace is important. The rule applied is that the prefix on the terminating marker will be removed from each each line in the HEREDOC, providing all the lines have that prefix (i.e. every line is at least as indented as the terminating marker, and using the same mechanism of tabs vs spaces).
This commit is contained in:
parent
3ad5dd62fd
commit
f5480db646
@ -94,7 +94,12 @@ func TestDecode_interface(t *testing.T) {
|
||||
{
|
||||
"multiline_indented.hcl",
|
||||
false,
|
||||
map[string]interface{}{"foo": " bar\n baz\n"},
|
||||
map[string]interface{}{"foo": " bar\n baz\n"},
|
||||
},
|
||||
{
|
||||
"multiline_no_hanging_indent.hcl",
|
||||
false,
|
||||
map[string]interface{}{"foo": " baz\n bar\n foo\n"},
|
||||
},
|
||||
{
|
||||
"multiline_no_eof.hcl",
|
||||
|
@ -142,14 +142,7 @@ func (t Token) Value() interface{} {
|
||||
case IDENT:
|
||||
return t.Text
|
||||
case HEREDOC:
|
||||
// We need to find the end of the marker
|
||||
idx := strings.IndexByte(t.Text, '\n')
|
||||
if idx == -1 {
|
||||
panic("heredoc doesn't contain newline")
|
||||
}
|
||||
|
||||
// Trim any trailing whitespace from the start of the marker
|
||||
return strings.TrimRight(string(t.Text[idx+1:len(t.Text)-idx+1]), " \t")
|
||||
return unindentHeredoc(t.Text)
|
||||
case STRING:
|
||||
// Determine the Unquote method to use. If it came from JSON,
|
||||
// then we need to use the built-in unquote since we have to
|
||||
@ -169,3 +162,53 @@ func (t Token) Value() interface{} {
|
||||
panic(fmt.Sprintf("unimplemented Value for type: %s", t.Type))
|
||||
}
|
||||
}
|
||||
|
||||
// unindentHeredoc returns the string content of a HEREDOC if it is started with <<
|
||||
// and the content of a HEREDOC with the hanging indent removed if it is started with
|
||||
// a <<-, and the terminating line is at least as indented as the least indented line.
|
||||
func unindentHeredoc(heredoc string) string {
|
||||
// We need to find the end of the marker
|
||||
idx := strings.IndexByte(heredoc, '\n')
|
||||
if idx == -1 {
|
||||
panic("heredoc doesn't contain newline")
|
||||
}
|
||||
|
||||
unindent := heredoc[2] == '-'
|
||||
|
||||
// We can optimize if the heredoc isn't marked for indentation
|
||||
if !unindent {
|
||||
return string(heredoc[idx+1 : len(heredoc)-idx+1])
|
||||
}
|
||||
|
||||
// We need to unindent each line based on the indentation level of the marker
|
||||
lines := strings.Split(string(heredoc[idx+1:len(heredoc)-idx+2]), "\n")
|
||||
whitespacePrefix := lines[len(lines)-1]
|
||||
|
||||
isIndented := true
|
||||
for _, v := range lines {
|
||||
if strings.HasPrefix(v, whitespacePrefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
isIndented = false
|
||||
break
|
||||
}
|
||||
|
||||
// If all lines are not at least as indented as the terminating mark, return the
|
||||
// heredoc as is, but trim the leading space from the marker on the final line.
|
||||
if !isIndented {
|
||||
return strings.TrimRight(string(heredoc[idx+1:len(heredoc)-idx+1]), " \t")
|
||||
}
|
||||
|
||||
unindentedLines := make([]string, len(lines))
|
||||
for k, v := range lines {
|
||||
if k == len(lines)-1 {
|
||||
unindentedLines[k] = ""
|
||||
break
|
||||
}
|
||||
|
||||
unindentedLines[k] = strings.TrimPrefix(v, whitespacePrefix)
|
||||
}
|
||||
|
||||
return strings.Join(unindentedLines, "\n")
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
foo = <<-EOF
|
||||
bar
|
||||
baz
|
||||
EOF
|
||||
EOF
|
||||
|
5
test-fixtures/multiline_no_hanging_indent.hcl
Normal file
5
test-fixtures/multiline_no_hanging_indent.hcl
Normal file
@ -0,0 +1,5 @@
|
||||
foo = <<-EOF
|
||||
baz
|
||||
bar
|
||||
foo
|
||||
EOF
|
Loading…
Reference in New Issue
Block a user