cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.17.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/models.go

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