cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.71.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/models.go

376lines · modecode

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