cloudflare/pint

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v0.62.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

internal/parser/read.go

173lines · modecode

1package parser
2
3import (
4 "bufio"
5 "errors"
6 "io"
7 "strings"
8
9 "github.com/cloudflare/pint/internal/comments"
10)
11
12type skipMode uint8
13
14const (
15 skipNone skipMode = iota
16 skipNextLine
17 skipBegin
18 skipEnd
19 skipCurrentLine
20 skipFile
21)
22
23func emptyLine(line string, comments []comments.Comment, stripComments bool) string {
24 offset := len(line)
25 for _, c := range comments {
26 offset = c.Offset
27 break
28 }
29
30 var buf strings.Builder
31 for i, r := range line {
32 switch {
33 case r == '\n':
34 buf.WriteRune(r)
35 case i < offset || stripComments:
36 buf.WriteRune(' ')
37 default:
38 buf.WriteRune(r)
39 }
40 }
41
42 return buf.String()
43}
44
45type Content struct {
46 Body []byte
47 TotalLines int
48 IgnoreLine int
49 Ignored bool
50}
51
52func ReadContent(r io.Reader) (out Content, fileComments []comments.Comment, err error) {
53 reader := bufio.NewReader(r)
54 var (
55 lineno int
56 line string
57 lineComments []comments.Comment
58 found bool
59 skip skipMode
60
61 skipNext bool
62 autoReset bool
63 skipAll bool
64 inBegin bool
65 )
66
67 for {
68 lineno++
69 line, err = reader.ReadString('\n')
70 if err != nil && !errors.Is(err, io.EOF) {
71 break
72 }
73 if line != "" {
74 out.TotalLines++
75 }
76
77 lineComments = comments.Parse(lineno, line)
78
79 if skipAll {
80 out.Body = append(out.Body, []byte(emptyLine(line, lineComments, inBegin))...)
81 } else {
82 skip = skipNone
83 found = false
84 for _, comment := range lineComments {
85 // nolint:exhaustive
86 switch comment.Type {
87 case comments.IgnoreFileType:
88 skip = skipFile
89 found = true
90 case comments.IgnoreLineType:
91 skip = skipCurrentLine
92 found = true
93 case comments.IgnoreBeginType:
94 skip = skipBegin
95 found = true
96 case comments.IgnoreEndType:
97 skip = skipEnd
98 found = true
99 case comments.IgnoreNextLineType:
100 skip = skipNextLine
101 found = true
102 case comments.FileOwnerType:
103 fileComments = append(fileComments, comment)
104 case comments.RuleOwnerType:
105 // pass
106 case comments.FileDisableType:
107 fileComments = append(fileComments, comment)
108 case comments.DisableType:
109 // pass
110 case comments.FileSnoozeType:
111 fileComments = append(fileComments, comment)
112 case comments.SnoozeType:
113 // pass
114 case comments.RuleSetType:
115 // pass
116 case comments.InvalidComment:
117 fileComments = append(fileComments, comment)
118 }
119 }
120 switch {
121 case found:
122 switch skip {
123 case skipNone:
124 // no-op
125 case skipFile:
126 out.Ignored = true
127 out.IgnoreLine = lineno
128 out.Body = append(out.Body, []byte(emptyLine(line, lineComments, inBegin))...)
129 skipNext = true
130 autoReset = false
131 skipAll = true
132 case skipCurrentLine:
133 out.Body = append(out.Body, []byte(emptyLine(line, lineComments, inBegin))...)
134 if !inBegin {
135 skipNext = false
136 autoReset = true
137 }
138 case skipNextLine:
139 out.Body = append(out.Body, []byte(line)...)
140 skipNext = true
141 autoReset = true
142 case skipBegin:
143 out.Body = append(out.Body, []byte(line)...)
144 skipNext = true
145 autoReset = false
146 inBegin = true
147 case skipEnd:
148 out.Body = append(out.Body, []byte(line)...)
149 skipNext = false
150 autoReset = true
151 inBegin = false
152 }
153 case skipNext:
154 out.Body = append(out.Body, []byte(emptyLine(line, lineComments, inBegin))...)
155 if autoReset {
156 skipNext = false
157 }
158 default:
159 out.Body = append(out.Body, []byte(line)...)
160 }
161 }
162
163 if err != nil {
164 break
165 }
166 }
167
168 if !errors.Is(err, io.EOF) {
169 return out, fileComments, err
170 }
171
172 return out, fileComments, nil
173}
174