configs/configupgrade: Decide on blank lines by ends of items

Previously we were using the line count difference between the start of
one item and the next to decide whether to insert a blank line between
two items, but that is incorrect for multi-line items.

Instead, we'll now count the difference from the final line of the
previous item to the first line of the next, as best we can with the
limited position info recorded by the HCL1 parser.
This commit is contained in:
Martin Atkins 2018-11-30 17:42:28 -08:00
parent bdb724562c
commit e49d993d89
1 changed files with 25 additions and 3 deletions

View File

@ -1,10 +1,10 @@
package configupgrade
import (
"log"
"bytes"
"fmt"
"io"
"log"
"sort"
"strings"
@ -234,7 +234,7 @@ func (u *Upgrader) upgradeNativeSyntaxFile(filename string, src []byte, an *anal
// to retain that separation.
if (i + 1) < len(args) {
next := args[i+1]
thisPos := arg.Pos()
thisPos := hcl1NodeEndPos(arg)
nextPos := next.Pos()
if nextPos.Line-thisPos.Line > 1 {
buf.WriteByte('\n')
@ -441,7 +441,7 @@ func (u *Upgrader) upgradeBlockBody(filename string, blockAddr string, buf *byte
// to retain that separation.
if (i + 1) < len(args) {
next := args[i+1]
thisPos := arg.Pos()
thisPos := hcl1NodeEndPos(arg)
nextPos := next.Pos()
if nextPos.Line-thisPos.Line > 1 {
buf.WriteByte('\n')
@ -583,6 +583,28 @@ func (q *commentQueue) TakeBefore(node hcl1ast.Node) []*hcl1ast.CommentGroup {
return ret
}
// hcl1NodeEndPos tries to find the latest possible position in the given
// node. This is primarily to try to find the last line number of a multi-line
// construct and is a best-effort sort of thing because HCL1 only tracks
// start positions for tokens and has no generalized way to find the full
// range for a single node.
func hcl1NodeEndPos(node hcl1ast.Node) hcl1token.Pos {
switch tn := node.(type) {
case *hcl1ast.ObjectItem:
if tn.LineComment != nil && len(tn.LineComment.List) > 0 {
return tn.LineComment.List[len(tn.LineComment.List)-1].Start
}
return hcl1NodeEndPos(tn.Val)
case *hcl1ast.ListType:
return tn.Rbrack
case *hcl1ast.ObjectType:
return tn.Rbrace
default:
// If all else fails, we'll just return the position of what we were given.
return tn.Pos()
}
}
func hcl1ErrSubjectRange(filename string, err error) *hcl2.Range {
if pe, isPos := err.(*hcl1parser.PosError); isPos {
return hcl1PosRange(filename, pe.Pos).Ptr()