snapshot of c000b74a5b09c433f96a69fa102c5c8f6583dff0 Annotations about the code that implements koment.

internal/commentpolicy/marker.go

1 package commentpolicy
2
3 import (
4 "bytes"
5 "strings"
6
7 "github.com/koment-dev/koment/internal/policy"
8 )
9
10 const binarySniffLimit = 8 << 10
11
12 type markerDetector struct{}
13
14 func (markerDetector) Handles(file string) bool {
15 _, commentable := syntaxFor(file)
16 return commentable
17 }
18
19 func (markerDetector) Name() string { return "marker scan" }
20
21 func (markerDetector) Scan(file string, content []byte, configured policy.Policy) ([]SourceComment, []bool, error) {
22 syntax, commentable := syntaxFor(file)
23 if !commentable || isBinary(content) {
24 return nil, nil, nil
25 }
26
27 spans := scanSpans(content, syntax)
28 comments := make([]SourceComment, 0, len(spans))
29 intrinsic := make([]bool, 0, len(spans))
30 for _, span := range spans {
31 raw := string(content[span.start:span.end])
32 body := markerBody(raw, syntax)
33 comments = append(comments, SourceComment{
34 File: file, Raw: raw, Body: body, Line: span.line,
35 Start: span.start, End: span.end,
36 })
37 intrinsic = append(intrinsic, isMarkerIntrinsic(raw, body, span, syntax, configured))
38 }
39 return comments, intrinsic, nil
40 }
41
42 func isBinary(content []byte) bool {
43 head := content
44 if len(head) > binarySniffLimit {
45 head = head[:binarySniffLimit]
46 }
47 return bytes.IndexByte(head, 0) >= 0
48 }
49
50 type span struct {
51 start int
52 end int
53 line int
54 ownsLine bool
55 shebang bool
56 }
57
58 func scanSpans(content []byte, syntax commentSyntax) []span {
59 var spans []span
60 starts := lineStarts(content)
61
62 for index := 0; index < len(starts); index++ {
63 lineFrom := starts[index]
64 lineTo := lineEnd(content, starts, index)
65 text := string(content[lineFrom:lineTo])
66
67 at, block := commentStart(text, syntax)
68 if at < 0 {
69 continue
70 }
71
72 found := span{
73 start: lineFrom + at,
74 line: index + 1,
75 ownsLine: strings.TrimSpace(text[:at]) == "",
76 }
77 found.shebang = index == 0 && strings.HasPrefix(text, "#!")
78
79 if block.open != "" {
80 end, lastLine := blockEnd(content, starts, index, found.start+len(block.open), block.close)
81 found.end = end
82 spans = append(spans, found)
83 index = lastLine
84 continue
85 }
86
87 found.end = lineTo
88 if found.ownsLine && !found.shebang && !isDirectiveLine(text, syntax) {
89 index = extendLineGroup(content, starts, index, syntax, &found)
90 }
91 spans = append(spans, found)
92 }
93 return spans
94 }
95
96 func extendLineGroup(content []byte, starts []int, index int, syntax commentSyntax, group *span) int {
97 last := index
98 for next := index + 1; next < len(starts); next++ {
99 lineFrom := starts[next]
100 lineTo := lineEnd(content, starts, next)
101 text := string(content[lineFrom:lineTo])
102 at, block := commentStart(text, syntax)
103 if at < 0 || block.open != "" || strings.TrimSpace(text[:at]) != "" || isDirectiveLine(text, syntax) {
104 break
105 }
106 group.end = lineTo
107 last = next
108 }
109 return last
110 }
111
112 func isDirectiveLine(text string, syntax commentSyntax) bool {
113 return matchesAnyDirective(markerBody(strings.TrimSpace(text), syntax), syntax.directives)
114 }
115
116 func blockEnd(content []byte, starts []int, index, from int, closing string) (int, int) {
117 relative := bytes.Index(content[from:], []byte(closing))
118 if relative < 0 {
119 return len(content), len(starts) - 1
120 }
121 end := from + relative + len(closing)
122 line := index
123 for line+1 < len(starts) && starts[line+1] <= end {
124 line++
125 }
126 return end, line
127 }
128
129 func commentStart(text string, syntax commentSyntax) (int, blockDelimiter) {
130 best, bestBlock := -1, blockDelimiter{}
131 consider := func(at int, block blockDelimiter) {
132 if at < 0 || (best >= 0 && at >= best) {
133 return
134 }
135 if !markerIsReal(text, at) {
136 return
137 }
138 best, bestBlock = at, block
139 }
140 for _, block := range syntax.block {
141 consider(strings.Index(text, block.open), block)
142 }
143 for _, marker := range syntax.line {
144 consider(strings.Index(text, marker), blockDelimiter{})
145 }
146 return best, bestBlock
147 }
148
149 func markerIsReal(text string, at int) bool {
150 before := text[:at]
151 if strings.TrimSpace(before) != "" && !strings.HasSuffix(before, " ") && !strings.HasSuffix(before, "\t") {
152 return false
153 }
154 return !insideQuotes(before)
155 }
156
157 func insideQuotes(before string) bool {
158 single, double, escaped := 0, 0, false
159 for _, character := range before {
160 switch {
161 case escaped:
162 escaped = false
163 case character == '\\':
164 escaped = true
165 case character == '\'' && double%2 == 0:
166 single++
167 case character == '"' && single%2 == 0:
168 double++
169 }
170 }
171 return single%2 == 1 || double%2 == 1
172 }
173
174 func markerBody(raw string, syntax commentSyntax) string {
175 lines := strings.Split(raw, "\n")
176 cleaned := make([]string, 0, len(lines))
177 for _, line := range lines {
178 line = strings.TrimSpace(line)
179 for _, block := range syntax.block {
180 line = strings.TrimSpace(strings.TrimPrefix(line, block.open))
181 line = strings.TrimSpace(strings.TrimSuffix(line, block.close))
182 }
183 for _, marker := range syntax.line {
184 line = strings.TrimSpace(strings.TrimPrefix(line, marker))
185 }
186 line = strings.TrimSpace(strings.TrimPrefix(line, "*"))
187 cleaned = append(cleaned, line)
188 }
189 return strings.TrimSpace(strings.Join(cleaned, "\n"))
190 }
191
192 func isMarkerIntrinsic(raw, body string, found span, syntax commentSyntax, configured policy.Policy) bool {
193 switch {
194 case isManagedRegionMarker(body):
195 return true
196 case found.shebang && configured.Allows(policy.IntrinsicToolchain):
197 return true
198 case configured.Allows(policy.IntrinsicDeprecated) && strings.Contains(body, "Deprecated:"):
199 return true
200 case configured.Allows(policy.IntrinsicUpstreamLink) &&
201 (strings.Contains(raw, "https://") || strings.Contains(raw, "http://")):
202 return true
203 case configured.Allows(policy.IntrinsicGeneratedMarker) && isGeneratedMarker(body):
204 return true
205 case configured.Allows(policy.IntrinsicToolchain) && hasConfiguredDirective(body, syntax):
206 return true
207 case configured.MatchesAllowedAnnotation(body):
208 return true
209 default:
210 return false
211 }
212 }
213
214 func isManagedRegionMarker(body string) bool {
215 return strings.HasPrefix(strings.TrimSpace(body), "koment:managed-")
216 }
217
218 func isGeneratedMarker(body string) bool {
219 upper := strings.ToUpper(body)
220 return strings.Contains(upper, "DO NOT EDIT") ||
221 strings.Contains(upper, "@GENERATED") ||
222 (strings.Contains(body, "Code generated") && strings.Contains(upper, "DO NOT EDIT"))
223 }
224
225 func hasConfiguredDirective(body string, syntax commentSyntax) bool {
226 if body == "" {
227 return false
228 }
229 for _, line := range strings.Split(body, "\n") {
230 line = strings.TrimSpace(line)
231 if line == "" {
232 continue
233 }
234 if !matchesAnyDirective(line, syntax.directives) {
235 return false
236 }
237 }
238 return true
239 }
240
241 func matchesAnyDirective(line string, directives []string) bool {
242 for _, prefix := range directives {
243 if strings.HasPrefix(line, prefix) {
244 return true
245 }
246 }
247 return false
248 }

Find an annotation

Search file paths, rationale, kinds, and authors.

moveEnter openEsc close