cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.26.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/models.go

391lines · modecode

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