cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.33.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/models.go

429lines · modecode

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