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 }