cloudflare/pint

Public

mirrored from https://github.com/cloudflare/pintAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.57.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

internal/parser/models.go

360lines · modecode

1package parser
2
3import (
4 "fmt"
5 "strconv"
6 "strings"
7
8 "golang.org/x/exp/slices"
9 "gopkg.in/yaml.v3"
10
11 "github.com/cloudflare/pint/internal/comments"
12)
13
14func nodeLines(node *yaml.Node, offset int) (lr LineRange) {
15 switch {
16 case node.Value == "":
17 lr.First = node.Line + offset
18 case node.Style == yaml.LiteralStyle || node.Style == yaml.FoldedStyle:
19 lr.First = node.Line + 1 + offset
20 default:
21 lr.First = node.Line + offset
22 }
23 lr.Last = lr.First + len(strings.Split(strings.TrimSuffix(node.Value, "\n"), "\n")) - 1
24 return lr
25}
26
27func nodeValue(node *yaml.Node) string {
28 if node.Alias != nil {
29 return node.Alias.Value
30 }
31 return node.Value
32}
33
34func mergeComments(node *yaml.Node) (comments []string) {
35 if node.HeadComment != "" {
36 comments = append(comments, node.HeadComment)
37 }
38 if node.LineComment != "" {
39 comments = append(comments, node.LineComment)
40 }
41 if node.FootComment != "" {
42 comments = append(comments, node.FootComment)
43 }
44 for _, child := range node.Content {
45 comments = append(comments, mergeComments(child)...)
46 }
47 return comments
48}
49
50type YamlNode struct {
51 Value string
52 Lines LineRange
53}
54
55func (yn *YamlNode) IsIdentical(b *YamlNode) bool {
56 if (yn == nil) != (b == nil) {
57 return false
58 }
59 if yn == nil {
60 return true
61 }
62 if yn.Value != b.Value {
63 return false
64 }
65 return true
66}
67
68func newYamlNode(node *yaml.Node, offset int) *YamlNode {
69 n := YamlNode{
70 Lines: nodeLines(node, offset),
71 Value: nodeValue(node),
72 }
73 return &n
74}
75
76func newYamlNodeWithKey(key, node *yaml.Node, offset int) *YamlNode {
77 keyLines := nodeLines(key, offset)
78 valLines := nodeLines(node, offset)
79 n := YamlNode{
80 Lines: LineRange{
81 First: min(keyLines.First, valLines.First),
82 Last: max(keyLines.Last, valLines.Last),
83 },
84 Value: nodeValue(node),
85 }
86 return &n
87}
88
89type YamlKeyValue struct {
90 Key *YamlNode
91 Value *YamlNode
92}
93
94type YamlMap struct {
95 Key *YamlNode
96 Items []*YamlKeyValue
97 Lines LineRange
98}
99
100func (ym *YamlMap) IsIdentical(b *YamlMap) bool {
101 var al, bl []string
102
103 if ym != nil && ym.Items != nil {
104 al = make([]string, 0, len(ym.Items))
105 for _, kv := range ym.Items {
106 al = append(al, fmt.Sprintf("%s: %s", kv.Key.Value, kv.Value.Value))
107 }
108 slices.Sort(al)
109 }
110
111 if b != nil && b.Items != nil {
112 bl = make([]string, 0, len(b.Items))
113 for _, kv := range b.Items {
114 bl = append(bl, fmt.Sprintf("%s: %s", kv.Key.Value, kv.Value.Value))
115 }
116 slices.Sort(bl)
117 }
118
119 return slices.Equal(al, bl)
120}
121
122func (ym YamlMap) GetValue(key string) *YamlNode {
123 for _, child := range ym.Items {
124 if child.Key.Value == key {
125 return child.Value
126 }
127 }
128 return nil
129}
130
131func newYamlMap(key, value *yaml.Node, offset int) *YamlMap {
132 ym := YamlMap{
133 Lines: LineRange{
134 First: key.Line + offset,
135 Last: key.Line + offset,
136 },
137 Key: newYamlNode(key, offset),
138 }
139
140 var ckey *yaml.Node
141 for _, child := range value.Content {
142 if ckey != nil {
143 kv := YamlKeyValue{
144 Key: newYamlNode(ckey, offset),
145 Value: newYamlNode(child, offset),
146 }
147 if kv.Value.Lines.Last > ym.Lines.Last {
148 ym.Lines.Last = kv.Value.Lines.Last
149 }
150 ym.Items = append(ym.Items, &kv)
151 ckey = nil
152 } else {
153 ckey = child
154 }
155 }
156
157 return &ym
158}
159
160func (pqle PromQLExpr) IsIdentical(b PromQLExpr) bool {
161 return pqle.Value.Value == b.Value.Value
162}
163
164func newPromQLExpr(key, val *yaml.Node, offset int) *PromQLExpr {
165 expr := PromQLExpr{
166 Value: newYamlNodeWithKey(key, val, offset),
167 }
168
169 qlNode, err := DecodeExpr(expr.Value.Value)
170 if err != nil {
171 expr.SyntaxError = err
172 return &expr
173
174 }
175 expr.Query = qlNode
176 return &expr
177}
178
179type AlertingRule struct {
180 Expr PromQLExpr
181 For *YamlNode
182 KeepFiringFor *YamlNode
183 Labels *YamlMap
184 Annotations *YamlMap
185 Alert YamlNode
186}
187
188func (ar *AlertingRule) IsIdentical(b *AlertingRule) bool {
189 if (ar == nil) != (b == nil) {
190 return false
191 }
192 if ar == nil {
193 return true
194 }
195 if !ar.Alert.IsIdentical(&b.Alert) {
196 return false
197 }
198 if !ar.Expr.IsIdentical(b.Expr) {
199 return false
200 }
201 if !ar.For.IsIdentical(b.For) {
202 return false
203 }
204 if !ar.KeepFiringFor.IsIdentical(b.KeepFiringFor) {
205 return false
206 }
207 if !ar.Labels.IsIdentical(b.Labels) {
208 return false
209 }
210 if !ar.Annotations.IsIdentical(b.Annotations) {
211 return false
212 }
213 return true
214}
215
216type RecordingRule struct {
217 Expr PromQLExpr
218 Labels *YamlMap
219 Record YamlNode
220}
221
222func (rr *RecordingRule) IsIdentical(b *RecordingRule) bool {
223 if (rr == nil) != (b == nil) {
224 return false
225 }
226 if rr == nil {
227 return true
228 }
229 if !rr.Record.IsIdentical(&b.Record) {
230 return false
231 }
232 if !rr.Expr.IsIdentical(b.Expr) {
233 return false
234 }
235 if !rr.Labels.IsIdentical(b.Labels) {
236 return false
237 }
238 return true
239}
240
241type ParseError struct {
242 Err error
243 Fragment string
244 Line int
245}
246
247type LineRange struct {
248 First int
249 Last int
250}
251
252func (lr LineRange) String() string {
253 if lr.First == lr.Last {
254 return strconv.Itoa(lr.First)
255 }
256 return fmt.Sprintf("%d-%d", lr.First, lr.Last)
257}
258
259func (lr LineRange) Expand() []int {
260 lines := make([]int, 0, lr.Last-lr.First+1)
261 for i := lr.First; i <= lr.Last; i++ {
262 lines = append(lines, i)
263 }
264 return lines
265}
266
267type Rule struct {
268 AlertingRule *AlertingRule
269 RecordingRule *RecordingRule
270 Error ParseError
271 Comments []comments.Comment
272 Lines LineRange
273}
274
275func (r Rule) IsIdentical(b Rule) bool {
276 if r.Type() != b.Type() {
277 return false
278 }
279 if !r.AlertingRule.IsIdentical(b.AlertingRule) {
280 return false
281 }
282 if !r.RecordingRule.IsIdentical(b.RecordingRule) {
283 return false
284 }
285
286 ac := make([]string, 0, len(r.Comments))
287 for _, c := range r.Comments {
288 ac = append(ac, c.Value.String())
289 }
290 slices.Sort(ac)
291
292 bc := make([]string, 0, len(r.Comments))
293 for _, c := range b.Comments {
294 bc = append(bc, c.Value.String())
295 }
296 slices.Sort(bc)
297
298 return slices.Equal(ac, bc)
299}
300
301func (r Rule) IsSame(nr Rule) bool {
302 if (r.AlertingRule != nil) != (nr.AlertingRule != nil) {
303 return false
304 }
305 if (r.RecordingRule != nil) != (nr.RecordingRule != nil) {
306 return false
307 }
308 if r.Error != nr.Error {
309 return false
310 }
311 if r.Lines.First != nr.Lines.First {
312 return false
313 }
314 if r.Lines.Last != nr.Lines.Last {
315 return false
316 }
317 return true
318}
319
320func (r Rule) Name() string {
321 if r.RecordingRule != nil {
322 return r.RecordingRule.Record.Value
323 }
324 if r.AlertingRule != nil {
325 return r.AlertingRule.Alert.Value
326 }
327 return ""
328}
329
330func (r Rule) Expr() PromQLExpr {
331 if r.RecordingRule != nil {
332 return r.RecordingRule.Expr
333 }
334 return r.AlertingRule.Expr
335}
336
337type RuleType string
338
339const (
340 AlertingRuleType RuleType = "alerting"
341 RecordingRuleType RuleType = "recording"
342 InvalidRuleType RuleType = "invalid"
343)
344
345func (r Rule) Type() RuleType {
346 if r.AlertingRule != nil {
347 return AlertingRuleType
348 }
349 if r.RecordingRule != nil {
350 return RecordingRuleType
351 }
352 return InvalidRuleType
353}
354
355type Result struct {
356 Path string
357 Error error
358 Content []byte
359 Rules []Rule
360}
361