github.com/Azure/tflint-ruleset-azurerm-ext@v0.6.0/rules/argument.go (about)

     1  package rules
     2  
     3  import (
     4  	"github.com/hashicorp/hcl/v2"
     5  	"github.com/hashicorp/hcl/v2/hclsyntax"
     6  	"github.com/hashicorp/hcl/v2/hclwrite"
     7  	"math"
     8  	"sort"
     9  	"strings"
    10  )
    11  
    12  // Section is an interface offering general APIs of argument collections
    13  type Section interface {
    14  	// CheckOrder checks whether the arguments in the collection is sorted
    15  	CheckOrder() bool
    16  
    17  	// ToString prints arguments in the collection in order
    18  	ToString() string
    19  
    20  	// GetRange returns the entire range of the argument collection
    21  	GetRange() *hcl.Range
    22  }
    23  
    24  func toString(sections ...Section) string {
    25  	var lines []string
    26  	for _, section := range sections {
    27  		line := section.ToString()
    28  		if line != "" {
    29  			lines = append(lines, line)
    30  		}
    31  	}
    32  	return strings.Join(lines, "\n")
    33  }
    34  
    35  func mergeRange(sections ...Section) *hcl.Range {
    36  	start := hcl.Pos{Line: math.MaxInt}
    37  	end := hcl.Pos{Line: -1}
    38  	filename := ""
    39  	isNil := true
    40  	for _, section := range sections {
    41  		r := section.GetRange()
    42  		if r == nil {
    43  			continue
    44  		}
    45  		isNil = false
    46  		if filename == "" {
    47  			filename = r.Filename
    48  		}
    49  		if r.Start.Line < start.Line {
    50  			start = r.Start
    51  		}
    52  		if r.End.Line > end.Line {
    53  			end = r.End
    54  		}
    55  	}
    56  	if isNil {
    57  		return nil
    58  	}
    59  	return &hcl.Range{
    60  		Filename: filename,
    61  		Start:    start,
    62  		End:      end,
    63  	}
    64  }
    65  
    66  // Arg is a wrapper of the attribute
    67  type Arg struct {
    68  	Name  string
    69  	Range hcl.Range
    70  	File  *hcl.File
    71  }
    72  
    73  // ToString prints the arg content
    74  func (a *Arg) ToString() string {
    75  	return string(hclwrite.Format(a.Range.SliceBytes(a.File.Bytes)))
    76  }
    77  
    78  // Args is the collection of args with the same type
    79  type Args struct {
    80  	Args  []*Arg
    81  	Range *hcl.Range
    82  }
    83  
    84  // CheckOrder checks whether this type of args are sorted
    85  func (a *Args) CheckOrder() bool {
    86  	if a == nil {
    87  		return true
    88  	}
    89  	var name *string
    90  	for _, arg := range a.Args {
    91  		if name != nil && *name > arg.Name {
    92  			return false
    93  		}
    94  		name = &arg.Name
    95  	}
    96  	return true
    97  }
    98  
    99  // ToString prints this type of args in order
   100  func (a *Args) ToString() string {
   101  	if a == nil {
   102  		return ""
   103  	}
   104  	sortedArgs := make([]*Arg, len(a.Args))
   105  	copy(sortedArgs, a.Args)
   106  	sort.Slice(sortedArgs, func(i, j int) bool {
   107  		return sortedArgs[i].Name < sortedArgs[j].Name
   108  	})
   109  	var lines []string
   110  	for _, arg := range sortedArgs {
   111  		lines = append(lines, arg.ToString())
   112  	}
   113  	return string(hclwrite.Format([]byte(strings.Join(lines, "\n"))))
   114  }
   115  
   116  // GetRange returns the entire range of this type of args
   117  func (a *Args) GetRange() *hcl.Range {
   118  	if a == nil {
   119  		return nil
   120  	}
   121  	return a.Range
   122  }
   123  
   124  // HeadMetaArgs is the collection of head meta args
   125  type HeadMetaArgs struct {
   126  	Args  []*Arg
   127  	Range *hcl.Range
   128  }
   129  
   130  // CheckOrder checks whether the head meta args are sorted
   131  func (a *HeadMetaArgs) CheckOrder() bool {
   132  	if a == nil {
   133  		return true
   134  	}
   135  	score := math.MaxInt
   136  	for _, arg := range a.Args {
   137  		if score < headMetaArgPriority[arg.Name] {
   138  			return false
   139  		}
   140  		score = headMetaArgPriority[arg.Name]
   141  	}
   142  	return true
   143  }
   144  
   145  // ToString prints the head meta args in order
   146  func (a *HeadMetaArgs) ToString() string {
   147  	if a == nil {
   148  		return ""
   149  	}
   150  	sortedArgs := make([]*Arg, len(a.Args))
   151  	copy(sortedArgs, a.Args)
   152  	sort.Slice(sortedArgs, func(i, j int) bool {
   153  		return headMetaArgPriority[sortedArgs[i].Name] > headMetaArgPriority[sortedArgs[j].Name]
   154  	})
   155  	var lines []string
   156  	for _, arg := range sortedArgs {
   157  		lines = append(lines, arg.ToString())
   158  	}
   159  	return string(hclwrite.Format([]byte(strings.Join(lines, "\n"))))
   160  }
   161  
   162  // GetRange returns the entire range of head meta args
   163  func (a *HeadMetaArgs) GetRange() *hcl.Range {
   164  	if a == nil {
   165  		return nil
   166  	}
   167  	return a.Range
   168  }
   169  
   170  func (a *Args) add(arg *Arg) {
   171  	a.Args = append(a.Args, arg)
   172  	a.updateRange(arg)
   173  }
   174  
   175  func (a *Args) updateRange(arg *Arg) {
   176  	if a.Range == nil {
   177  		a.Range = &hcl.Range{
   178  			Filename: arg.Range.Filename,
   179  			Start:    hcl.Pos{Line: math.MaxInt},
   180  			End:      hcl.Pos{Line: -1},
   181  		}
   182  	}
   183  	if a.Range.Start.Line > arg.Range.Start.Line {
   184  		a.Range.Start = arg.Range.Start
   185  	}
   186  	if a.Range.End.Line < arg.Range.End.Line {
   187  		a.Range.End = arg.Range.End
   188  	}
   189  }
   190  
   191  func (a *HeadMetaArgs) add(arg *Arg) {
   192  	a.Args = append(a.Args, arg)
   193  	a.updateRange(arg)
   194  }
   195  
   196  func (a *HeadMetaArgs) updateRange(arg *Arg) {
   197  	if a.Range == nil {
   198  		a.Range = &hcl.Range{
   199  			Filename: arg.Range.Filename,
   200  			Start:    hcl.Pos{Line: math.MaxInt},
   201  			End:      hcl.Pos{Line: -1},
   202  		}
   203  	}
   204  	if a.Range.Start.Line > arg.Range.Start.Line {
   205  		a.Range.Start = arg.Range.Start
   206  	}
   207  	if a.Range.End.Line < arg.Range.End.Line {
   208  		a.Range.End = arg.Range.End
   209  	}
   210  }
   211  
   212  func buildAttrArg(attr *hclsyntax.Attribute, file *hcl.File) *Arg {
   213  	return &Arg{
   214  		Name:  attr.Name,
   215  		Range: attr.SrcRange,
   216  		File:  file,
   217  	}
   218  }