rules/argument.go (143 lines of code) (raw):
package rules
import (
"math"
"sort"
"strings"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/hashicorp/hcl/v2/hclwrite"
)
// Section is an interface offering general APIs of argument collections
type Section interface {
// CheckOrder checks whether the arguments in the collection is sorted
CheckOrder() bool
// ToString prints arguments in the collection in order
ToString() string
// GetRange returns the entire range of the argument collection
GetRange() *hcl.Range
}
func toString(sections ...Section) string {
var lines []string
for _, section := range sections {
line := section.ToString()
if line != "" {
lines = append(lines, line)
}
}
return strings.Join(lines, "\n")
}
// Arg is a wrapper of the attribute
type Arg struct {
Name string
Range hcl.Range
File *hcl.File
}
// ToString prints the arg content
func (a *Arg) ToString() string {
return string(hclwrite.Format(a.Range.SliceBytes(a.File.Bytes)))
}
// Args is the collection of args with the same type
type Args struct {
Args []*Arg
Range *hcl.Range
}
// CheckOrder checks whether this type of args are sorted
func (a *Args) CheckOrder() bool {
return true
}
// ToString prints this type of args in order
func (a *Args) ToString() string {
if a == nil {
return ""
}
sortedArgs := make([]*Arg, len(a.Args))
copy(sortedArgs, a.Args)
sort.Slice(sortedArgs, func(i, j int) bool {
return sortedArgs[i].Range.Start.Line < sortedArgs[j].Range.Start.Line
})
var lines []string
for _, arg := range sortedArgs {
lines = append(lines, arg.ToString())
}
return string(hclwrite.Format([]byte(strings.Join(lines, "\n"))))
}
// GetRange returns the entire range of this type of args
func (a *Args) GetRange() *hcl.Range {
if a == nil {
return nil
}
return a.Range
}
// HeadMetaArgs is the collection of head meta args
type HeadMetaArgs struct {
Args []*Arg
Range *hcl.Range
}
// CheckOrder checks whether the head meta args are sorted
func (a *HeadMetaArgs) CheckOrder() bool {
if a == nil {
return true
}
score := math.MaxInt
for _, arg := range a.Args {
if score < headMetaArgPriority[arg.Name] {
return false
}
score = headMetaArgPriority[arg.Name]
}
return true
}
// ToString prints the head meta args in order
func (a *HeadMetaArgs) ToString() string {
if a == nil {
return ""
}
sortedArgs := make([]*Arg, len(a.Args))
copy(sortedArgs, a.Args)
sort.Slice(sortedArgs, func(i, j int) bool {
return headMetaArgPriority[sortedArgs[i].Name] > headMetaArgPriority[sortedArgs[j].Name]
})
var lines []string
for _, arg := range sortedArgs {
lines = append(lines, arg.ToString())
}
return string(hclwrite.Format([]byte(strings.Join(lines, "\n"))))
}
// GetRange returns the entire range of head meta args
func (a *HeadMetaArgs) GetRange() *hcl.Range {
if a == nil {
return nil
}
return a.Range
}
func (a *Args) add(arg *Arg) {
a.Args = append(a.Args, arg)
a.updateRange(arg)
}
func (a *Args) updateRange(arg *Arg) {
if a.Range == nil {
a.Range = &hcl.Range{
Filename: arg.Range.Filename,
Start: hcl.Pos{Line: math.MaxInt},
End: hcl.Pos{Line: -1},
}
}
if a.Range.Start.Line > arg.Range.Start.Line {
a.Range.Start = arg.Range.Start
}
if a.Range.End.Line < arg.Range.End.Line {
a.Range.End = arg.Range.End
}
}
func (a *HeadMetaArgs) add(arg *Arg) {
a.Args = append(a.Args, arg)
a.updateRange(arg)
}
func (a *HeadMetaArgs) updateRange(arg *Arg) {
if a.Range == nil {
a.Range = &hcl.Range{
Filename: arg.Range.Filename,
Start: hcl.Pos{Line: math.MaxInt},
End: hcl.Pos{Line: -1},
}
}
if a.Range.Start.Line > arg.Range.Start.Line {
a.Range.Start = arg.Range.Start
}
if a.Range.End.Line < arg.Range.End.Line {
a.Range.End = arg.Range.End
}
}
func buildAttrArg(attr *hclsyntax.Attribute, file *hcl.File) *Arg {
return &Arg{
Name: attr.Name,
Range: attr.SrcRange,
File: file,
}
}