cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.73.5

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/models.go

417lines · modecode

1package parser
2
3import (
4 "fmt"
5 "slices"
6 "time"
7
8 "gopkg.in/yaml.v3"
9
10 "github.com/cloudflare/pint/internal/comments"
11 "github.com/cloudflare/pint/internal/diags"
12)
13
14func nodeValue(node *yaml.Node) string {
15 if node.Alias != nil {
16 return node.Alias.Value
17 }
18 return node.Value
19}
20
21func mergeComments(node *yaml.Node) (comments []string) {
22 if node.HeadComment != "" {
23 comments = append(comments, node.HeadComment)
24 }
25 if node.LineComment != "" {
26 comments = append(comments, node.LineComment)
27 }
28 if node.FootComment != "" {
29 comments = append(comments, node.FootComment)
30 }
31 for _, child := range node.Content {
32 comments = append(comments, mergeComments(child)...)
33 }
34 return comments
35}
36
37type YamlNode struct {
38 Value string
39 Pos diags.PositionRanges
40}
41
42func (yn *YamlNode) IsIdentical(b *YamlNode) bool {
43 if (yn == nil) != (b == nil) {
44 return false
45 }
46 if yn == nil {
47 return true
48 }
49 if yn.Value != b.Value {
50 return false
51 }
52 return true
53}
54
55func newYamlNode(node *yaml.Node, offsetLine, offsetColumn int, contentLines []string, minColumn int) *YamlNode {
56 pos := diags.NewPositionRange(contentLines, node, minColumn)
57 pos.AddOffset(offsetLine, offsetColumn)
58 return &YamlNode{
59 Pos: pos,
60 Value: nodeValue(node),
61 }
62}
63
64type YamlKeyValue struct {
65 Key *YamlNode
66 Value *YamlNode
67}
68
69type YamlMap struct {
70 Key *YamlNode
71 Items []*YamlKeyValue
72}
73
74func (ym *YamlMap) IsIdentical(b *YamlMap) bool {
75 var al, bl []string
76
77 if ym != nil && ym.Items != nil {
78 al = make([]string, 0, len(ym.Items))
79 for _, kv := range ym.Items {
80 al = append(al, fmt.Sprintf("%s: %s", kv.Key.Value, kv.Value.Value))
81 }
82 slices.Sort(al)
83 }
84
85 if b != nil && b.Items != nil {
86 bl = make([]string, 0, len(b.Items))
87 for _, kv := range b.Items {
88 bl = append(bl, fmt.Sprintf("%s: %s", kv.Key.Value, kv.Value.Value))
89 }
90 slices.Sort(bl)
91 }
92
93 return slices.Equal(al, bl)
94}
95
96func (ym YamlMap) GetValue(key string) *YamlNode {
97 for _, child := range ym.Items {
98 if child.Key.Value == key {
99 return child.Value
100 }
101 }
102 return nil
103}
104
105func (ym *YamlMap) setValue(item *YamlKeyValue) {
106 for i := range ym.Items {
107 if ym.Items[i].Key.Value == item.Key.Value {
108 ym.Items[i].Value = item.Value
109 return
110 }
111 }
112 ym.Items = append(ym.Items, item)
113}
114
115func (ym YamlMap) Lines() (lr diags.LineRange) {
116 lr = ym.Key.Pos.Lines()
117 for _, item := range ym.Items {
118 lr.First = min(lr.First, item.Key.Pos.Lines().First)
119 lr.Last = max(lr.Last, item.Value.Pos.Lines().Last)
120 }
121 return lr
122}
123
124func newYamlMap(key, value *yaml.Node, offsetLine, offsetColumn int, contentLines []string) *YamlMap {
125 ym := YamlMap{
126 Key: newYamlNode(key, offsetLine, offsetColumn, contentLines, 1),
127 Items: nil,
128 }
129
130 var ckey *yaml.Node
131 for _, child := range value.Content {
132 if ckey != nil {
133 kv := YamlKeyValue{
134 Key: newYamlNode(ckey, offsetLine, offsetColumn, contentLines, key.Column+2),
135 Value: newYamlNode(child, offsetLine, offsetColumn, contentLines, ckey.Column+2),
136 }
137 ym.Items = append(ym.Items, &kv)
138 ckey = nil
139 } else {
140 ckey = child
141 }
142 }
143
144 return &ym
145}
146
147func (pqle PromQLExpr) IsIdentical(b PromQLExpr) bool {
148 return pqle.Value.Value == b.Value.Value
149}
150
151func newPromQLExpr(node *yaml.Node, offsetLine, offsetColumn int, contentLines []string, minColumn int) *PromQLExpr {
152 expr := PromQLExpr{
153 Value: newYamlNode(node, offsetLine, offsetColumn, contentLines, minColumn),
154 SyntaxError: nil,
155 Query: nil,
156 }
157
158 qlNode, err := DecodeExpr(expr.Value.Value)
159 if err != nil {
160 expr.SyntaxError = err
161 return &expr
162
163 }
164 expr.Query = qlNode
165 return &expr
166}
167
168type AlertingRule struct {
169 Expr PromQLExpr
170 For *YamlNode
171 KeepFiringFor *YamlNode
172 Labels *YamlMap
173 Annotations *YamlMap
174 Alert YamlNode
175}
176
177func (ar *AlertingRule) IsIdentical(b *AlertingRule) bool {
178 if (ar == nil) != (b == nil) {
179 return false
180 }
181 if ar == nil {
182 return true
183 }
184 if !ar.Alert.IsIdentical(&b.Alert) {
185 return false
186 }
187 if !ar.Expr.IsIdentical(b.Expr) {
188 return false
189 }
190 if !ar.For.IsIdentical(b.For) {
191 return false
192 }
193 if !ar.KeepFiringFor.IsIdentical(b.KeepFiringFor) {
194 return false
195 }
196 if !ar.Labels.IsIdentical(b.Labels) {
197 return false
198 }
199 if !ar.Annotations.IsIdentical(b.Annotations) {
200 return false
201 }
202 return true
203}
204
205type RecordingRule struct {
206 Expr PromQLExpr
207 Labels *YamlMap
208 Record YamlNode
209}
210
211func (rr *RecordingRule) IsIdentical(b *RecordingRule) bool {
212 if (rr == nil) != (b == nil) {
213 return false
214 }
215 if rr == nil {
216 return true
217 }
218 if !rr.Record.IsIdentical(&b.Record) {
219 return false
220 }
221 if !rr.Expr.IsIdentical(b.Expr) {
222 return false
223 }
224 if !rr.Labels.IsIdentical(b.Labels) {
225 return false
226 }
227 return true
228}
229
230// Use insread of StrictError.
231type ParseError struct {
232 Err error
233 Details string
234 Line int
235}
236
237func (pe ParseError) Error() string {
238 return fmt.Sprintf("error at line %d: %s", pe.Line, pe.Err)
239}
240
241type File struct {
242 Diagnostics []diags.Diagnostic
243 Comments []comments.Comment
244 Groups []Group
245 Error ParseError
246 TotalLines int
247 IsRelaxed bool
248 IsIgnored bool
249}
250
251type Group struct {
252 Labels *YamlMap
253 Name string
254 Error ParseError
255 Rules []Rule
256 Interval time.Duration
257 QueryOffset time.Duration
258 Limit int
259}
260
261type Rule struct {
262 AlertingRule *AlertingRule
263 RecordingRule *RecordingRule
264 Comments []comments.Comment
265 Error ParseError
266 Lines diags.LineRange
267}
268
269func (r Rule) IsIdentical(b Rule) bool {
270 if r.Type() != b.Type() {
271 return false
272 }
273 if !r.AlertingRule.IsIdentical(b.AlertingRule) {
274 return false
275 }
276 if !r.RecordingRule.IsIdentical(b.RecordingRule) {
277 return false
278 }
279
280 ac := make([]string, 0, len(r.Comments))
281 for _, c := range r.Comments {
282 ac = append(ac, c.Value.String())
283 }
284 slices.Sort(ac)
285
286 bc := make([]string, 0, len(r.Comments))
287 for _, c := range b.Comments {
288 bc = append(bc, c.Value.String())
289 }
290 slices.Sort(bc)
291
292 return slices.Equal(ac, bc)
293}
294
295func (r Rule) IsSame(nr Rule) bool {
296 if (r.AlertingRule != nil) != (nr.AlertingRule != nil) {
297 return false
298 }
299 if (r.RecordingRule != nil) != (nr.RecordingRule != nil) {
300 return false
301 }
302 if r.Error != nr.Error {
303 return false
304 }
305 if r.Lines.First != nr.Lines.First {
306 return false
307 }
308 if r.Lines.Last != nr.Lines.Last {
309 return false
310 }
311 return true
312}
313
314func (r Rule) Name() string {
315 if r.RecordingRule != nil {
316 return r.RecordingRule.Record.Value
317 }
318 if r.AlertingRule != nil {
319 return r.AlertingRule.Alert.Value
320 }
321 return ""
322}
323
324func (r Rule) NameNode() YamlNode {
325 if r.RecordingRule != nil {
326 return r.RecordingRule.Record
327 }
328 return r.AlertingRule.Alert
329}
330
331func (r Rule) Expr() PromQLExpr {
332 if r.RecordingRule != nil {
333 return r.RecordingRule.Expr
334 }
335 return r.AlertingRule.Expr
336}
337
338func (r Rule) LastKey() (node *YamlNode) {
339 if r.RecordingRule != nil {
340 node = &r.RecordingRule.Record
341 if r.RecordingRule.Expr.Value.Pos.Lines().Last > node.Pos.Lines().Last {
342 node = r.RecordingRule.Expr.Value
343 }
344 if r.RecordingRule.Labels != nil {
345 for _, lab := range r.RecordingRule.Labels.Items {
346 if lab.Key.Pos.Lines().Last > node.Pos.Lines().Last {
347 node = lab.Key
348 }
349 }
350 }
351 }
352 if r.AlertingRule != nil {
353 node = &r.AlertingRule.Alert
354 if r.AlertingRule.Expr.Value.Pos.Lines().Last > node.Pos.Lines().Last {
355 node = r.AlertingRule.Expr.Value
356 }
357 if r.AlertingRule.For != nil && r.AlertingRule.For.Pos.Lines().Last > node.Pos.Lines().Last {
358 node = r.AlertingRule.For
359 }
360 if r.AlertingRule.KeepFiringFor != nil && r.AlertingRule.KeepFiringFor.Pos.Lines().Last > node.Pos.Lines().Last {
361 node = r.AlertingRule.KeepFiringFor
362 }
363 if r.AlertingRule.Labels != nil {
364 for _, lab := range r.AlertingRule.Labels.Items {
365 if lab.Key.Pos.Lines().Last > node.Pos.Lines().Last {
366 node = lab.Key
367 }
368 }
369 }
370 if r.AlertingRule.Annotations != nil {
371 for _, ann := range r.AlertingRule.Annotations.Items {
372 if ann.Key.Pos.Lines().Last > node.Pos.Lines().Last {
373 node = ann.Key
374 }
375 }
376 }
377 }
378 return node
379}
380
381type RuleType string
382
383const (
384 AlertingRuleType RuleType = "alerting"
385 RecordingRuleType RuleType = "recording"
386 InvalidRuleType RuleType = "invalid"
387)
388
389func (r Rule) Type() RuleType {
390 if r.AlertingRule != nil {
391 return AlertingRuleType
392 }
393 if r.RecordingRule != nil {
394 return RecordingRuleType
395 }
396 return InvalidRuleType
397}
398
399func MergeMaps(a, b *YamlMap) *YamlMap {
400 if a == nil {
401 return b
402 }
403 if b == nil {
404 return a
405 }
406
407 dst := &YamlMap{
408 Key: a.Key,
409 Items: slices.Clone(a.Items),
410 }
411
412 for _, item := range b.Items {
413 dst.setValue(item)
414 }
415
416 return dst
417}
418