cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.28.1

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/models.go

425lines · modecode

1package parser
2
3import (
4 "strings"
5
6 "golang.org/x/exp/slices"
7 "gopkg.in/yaml.v3"
8
9 promparser "github.com/prometheus/prometheus/promql/parser"
10)
11
12func appendLine(lines []int, newLines ...int) []int {
13 for _, nl := range newLines {
14 var present bool
15 for _, l := range lines {
16 if l == nl {
17 present = true
18 break
19 }
20 }
21 if !present {
22 lines = append(lines, nl)
23 }
24 }
25
26 return lines
27}
28
29func nodeLines(node *yaml.Node, offset int) (lines []int) {
30 lineCount := len(strings.Split(strings.TrimSuffix(node.Value, "\n"), "\n"))
31
32 var firstLine int
33 // nolint: exhaustive
34 switch node.Style {
35 case yaml.LiteralStyle, yaml.FoldedStyle:
36 firstLine = node.Line + 1 + offset
37 default:
38 firstLine = node.Line + offset
39 }
40
41 for i := 0; i < lineCount; i++ {
42 lines = appendLine(lines, firstLine+i)
43 }
44
45 return lines
46}
47
48func NewFilePosition(l []int) FilePosition {
49 return FilePosition{Lines: l}
50}
51
52type FilePosition struct {
53 Lines []int
54}
55
56func (fp FilePosition) FirstLine() (line int) {
57 for _, l := range fp.Lines {
58 if line == 0 || l < line {
59 line = l
60 }
61 }
62 return
63}
64
65func (fp FilePosition) LastLine() (line int) {
66 for _, l := range fp.Lines {
67 if l > line {
68 line = l
69 }
70 }
71 return
72}
73
74func mergeComments(node *yaml.Node) (comments []string) {
75 if node.HeadComment != "" {
76 comments = append(comments, node.HeadComment)
77 }
78 if node.LineComment != "" {
79 comments = append(comments, node.LineComment)
80 }
81 if node.FootComment != "" {
82 comments = append(comments, node.FootComment)
83 }
84 return
85}
86
87type YamlNode struct {
88 Position FilePosition
89 Value string
90 Comments []string
91}
92
93func newYamlNode(node *yaml.Node, offset int) *YamlNode {
94 return &YamlNode{
95 Position: NewFilePosition(nodeLines(node, offset)),
96 Value: node.Value,
97 Comments: mergeComments(node),
98 }
99}
100
101func newYamlNodeWithParent(parent, node *yaml.Node, offset int) *YamlNode {
102 return &YamlNode{
103 Position: NewFilePosition(nodeLines(node, offset)),
104 Value: node.Value,
105 Comments: mergeComments(node),
106 }
107}
108
109func newYamlKeyValue(key, val *yaml.Node, offset int) *YamlKeyValue {
110 return &YamlKeyValue{
111 Key: newYamlNode(key, offset),
112 Value: newYamlNodeWithParent(key, val, offset),
113 }
114}
115
116type YamlKeyValue struct {
117 Key *YamlNode
118 Value *YamlNode
119}
120
121func (ykv YamlKeyValue) Lines() (lines []int) {
122 lines = appendLine(lines, ykv.Key.Position.Lines...)
123 lines = appendLine(lines, ykv.Value.Position.Lines...)
124 return
125}
126
127type YamlMap struct {
128 Key *YamlNode
129 Items []*YamlKeyValue
130}
131
132func (ym YamlMap) Lines() (lines []int) {
133 lines = appendLine(lines, ym.Key.Position.Lines...)
134 for _, item := range ym.Items {
135 lines = appendLine(lines, item.Lines()...)
136 }
137 return
138}
139
140func (ym YamlMap) GetValue(key string) *YamlNode {
141 for _, child := range ym.Items {
142 if child.Key.Value == key {
143 return child.Value
144 }
145 }
146 return nil
147}
148
149func newYamlMap(key, value *yaml.Node, offset int) *YamlMap {
150 ym := YamlMap{
151 Key: newYamlNode(key, offset),
152 }
153
154 var ckey *yaml.Node
155 for _, child := range value.Content {
156 if ckey != nil {
157 kv := YamlKeyValue{
158 Key: newYamlNode(ckey, offset),
159 Value: newYamlNode(child, offset),
160 }
161 ym.Items = append(ym.Items, &kv)
162 ckey = nil
163 } else {
164 ckey = child
165 }
166 }
167
168 return &ym
169}
170
171type PromQLNode struct {
172 Expr string
173 Node promparser.Expr
174 Children []*PromQLNode
175}
176
177type PromQLError struct {
178 node *PromQLNode
179 Err error
180}
181
182func (pqle PromQLError) Error() string {
183 return pqle.Err.Error()
184}
185
186func (pqle *PromQLError) Unwrap() error {
187 return pqle.Err
188}
189
190func (pqle PromQLError) Node() *PromQLNode {
191 return pqle.node
192}
193
194type PromQLExpr struct {
195 Key *YamlNode
196 Value *YamlNode
197 SyntaxError error
198 Query *PromQLNode
199}
200
201func (pqle PromQLExpr) Lines() (lines []int) {
202 lines = appendLine(lines, pqle.Key.Position.Lines...)
203 lines = appendLine(lines, pqle.Value.Position.Lines...)
204 return
205}
206
207func newPromQLExpr(key, val *yaml.Node, offset int) *PromQLExpr {
208 expr := PromQLExpr{
209 Key: newYamlNode(key, offset),
210 Value: newYamlNodeWithParent(key, val, offset),
211 }
212
213 qlNode, err := DecodeExpr(val.Value)
214 if err != nil {
215 expr.SyntaxError = err
216 return &expr
217
218 }
219 expr.Query = qlNode
220 return &expr
221}
222
223type AlertingRule struct {
224 Alert YamlKeyValue
225 Expr PromQLExpr
226 For *YamlKeyValue
227 Labels *YamlMap
228 Annotations *YamlMap
229}
230
231func (ar AlertingRule) Lines() (lines []int) {
232 lines = appendLine(lines, ar.Alert.Lines()...)
233 lines = appendLine(lines, ar.Expr.Lines()...)
234 if ar.For != nil {
235 lines = appendLine(lines, ar.For.Lines()...)
236 }
237 if ar.Labels != nil {
238 lines = appendLine(lines, ar.Labels.Lines()...)
239 }
240 if ar.Annotations != nil {
241 lines = appendLine(lines, ar.Annotations.Lines()...)
242 }
243 slices.Sort(lines)
244 return
245}
246
247func (ar AlertingRule) Comments() (comments []string) {
248 comments = append(comments, ar.Alert.Key.Comments...)
249 comments = append(comments, ar.Alert.Value.Comments...)
250 comments = append(comments, ar.Expr.Key.Comments...)
251 comments = append(comments, ar.Expr.Value.Comments...)
252 if ar.For != nil {
253 comments = append(comments, ar.For.Key.Comments...)
254 comments = append(comments, ar.For.Value.Comments...)
255 }
256 if ar.Labels != nil {
257 comments = append(comments, ar.Labels.Key.Comments...)
258 for _, label := range ar.Labels.Items {
259 comments = append(comments, label.Key.Comments...)
260 comments = append(comments, label.Value.Comments...)
261 }
262 }
263 if ar.Annotations != nil {
264 comments = append(comments, ar.Annotations.Key.Comments...)
265 for _, annotation := range ar.Annotations.Items {
266 comments = append(comments, annotation.Key.Comments...)
267 comments = append(comments, annotation.Value.Comments...)
268 }
269 }
270 return
271}
272
273type RecordingRule struct {
274 Record YamlKeyValue
275 Expr PromQLExpr
276 Labels *YamlMap
277}
278
279func (rr RecordingRule) Lines() (lines []int) {
280 lines = appendLine(lines, rr.Record.Lines()...)
281 lines = appendLine(lines, rr.Expr.Lines()...)
282 if rr.Labels != nil {
283 lines = appendLine(lines, rr.Labels.Lines()...)
284 }
285 slices.Sort(lines)
286 return
287}
288
289func (rr RecordingRule) Comments() (comments []string) {
290 comments = append(comments, rr.Record.Key.Comments...)
291 comments = append(comments, rr.Record.Value.Comments...)
292 comments = append(comments, rr.Expr.Key.Comments...)
293 comments = append(comments, rr.Expr.Value.Comments...)
294 if rr.Labels != nil {
295 comments = append(comments, rr.Labels.Key.Comments...)
296 for _, label := range rr.Labels.Items {
297 comments = append(comments, label.Key.Comments...)
298 comments = append(comments, label.Value.Comments...)
299 }
300 }
301 return
302}
303
304type ParseError struct {
305 Fragment string
306 Err error
307 Line int
308}
309
310type Rule struct {
311 AlertingRule *AlertingRule
312 RecordingRule *RecordingRule
313 Error ParseError
314}
315
316func (r Rule) IsSame(nr Rule) bool {
317 if (r.AlertingRule != nil) != (nr.AlertingRule != nil) {
318 return false
319 }
320 if (r.RecordingRule != nil) != (nr.RecordingRule != nil) {
321 return false
322 }
323 if r.Error != nr.Error {
324 return false
325 }
326 if !slices.Equal(r.Lines(), nr.Lines()) {
327 return false
328 }
329 return true
330}
331
332func (r Rule) Expr() PromQLExpr {
333 if r.RecordingRule != nil {
334 return r.RecordingRule.Expr
335 }
336 return r.AlertingRule.Expr
337}
338
339func (r Rule) Lines() []int {
340 if r.RecordingRule != nil {
341 return r.RecordingRule.Lines()
342 }
343 if r.AlertingRule != nil {
344 return r.AlertingRule.Lines()
345 }
346 if r.Error.Err != nil {
347 return []int{r.Error.Line}
348 }
349 return nil
350}
351
352func (r Rule) LineRange() []int {
353 var lmin, lmax int
354 for i, line := range r.Lines() {
355 if i == 0 {
356 lmin = line
357 lmax = line
358 continue
359 }
360 if line < lmin {
361 lmin = line
362 }
363 if line > lmax {
364 lmax = line
365 }
366 }
367
368 lines := []int{}
369 for i := lmin; i <= lmax; i++ {
370 lines = append(lines, i)
371 }
372 return lines
373}
374
375func (r Rule) HasComment(comment string) bool {
376 var comments []string
377 if r.RecordingRule != nil {
378 comments = r.RecordingRule.Comments()
379 } else if r.AlertingRule != nil {
380 comments = r.AlertingRule.Comments()
381 }
382 for _, c := range comments {
383 if hasComment(c, comment) {
384 return true
385 }
386 }
387 return false
388}
389
390func (r Rule) GetComment(comment ...string) (s Comment, ok bool) {
391 var comments []string
392 if r.RecordingRule != nil {
393 comments = r.RecordingRule.Comments()
394 } else if r.AlertingRule != nil {
395 comments = r.AlertingRule.Comments()
396 }
397 for _, c := range comments {
398 if val, ok := GetComment(c, comment...); ok {
399 return val, ok
400 }
401 }
402 return
403}
404
405func (r Rule) GetComments(key string) (cs []Comment) {
406 var comments []string
407 if r.RecordingRule != nil {
408 comments = r.RecordingRule.Comments()
409 } else if r.AlertingRule != nil {
410 comments = r.AlertingRule.Comments()
411 }
412 for _, c := range comments {
413 if val, ok := GetComment(c, key); ok {
414 cs = append(cs, val)
415 }
416 }
417 return cs
418}
419
420type Result struct {
421 Path string
422 Error error
423 Content []byte
424 Rules []Rule
425}