src/rules/style/noqa.bend
bolt@1.12.0.0 · 95 lines · 0 definitions
1# rule noqa: a noqa comment (src/noqa.bend) that silences nothing, as
2# ruff's RUF100. A bare one names no code, so it silences nothing; a code
3# it names silences nothing when no graded finding of the file, on the
4# mark's line, has that code, and a code that is no rule's never does. One
5# finding for a bare mark, and one for each such code, at the comment.
6#
7# It reads the graded findings of the whole run, so it is no per-file rule:
8# the planner runs it after every other rule and after the filter, and
9# what it reports no noqa comment silences. A project rule's code
10# (`coverage`, `unsafe`, `trace`) is judged only when the run is the whole
11# tree (`whole`): over files named, and in the editor, those rules see only
12# part of the laws, so their silence proves nothing.
13import Base
14import bolt@1.12.0.0/src/lazy/lazy.bend as Lazy
15import bolt@1.12.0.0/src/finding.bend as F
16import bolt@1.12.0.0/src/codes.bend as Codes
17import bolt@1.12.0.0/src/noqa.bend as Noqa
18
19# a project rule's code
20def project(+code: String) -> Bool:
21 Lazy.or_else(String.eq(code, Codes.code("coverage")),
22 _u => Lazy.or_else(String.eq(code, Codes.code("unsafe")), _v => String.eq(code, Codes.code("trace"))))
23
24# a code this run can judge: any, over the whole tree; a per-file rule's
25# (or no rule's) otherwise
26def judged(+whole: Bool, +code: String) -> Bool:
27 Lazy.or_else(whole, _u => Bool.not(project(code)))
28
29# some row of the table has the code
30def known.in(rows: List<&2, Codes.Entry>, +code: String) -> Bool:
31 match rows:
32 case Nil{}:
33 False{}
34 case Con{Codes.Entry{_s, id, _grp}, rest}:
35 Lazy.or_else(String.eq(id, code), _u => known.in(rest, code))
36
37# the code is a rule's
38def known(+code: String) -> Bool:
39 known.in(Codes.table(), code)
40
41# a graded finding at the path, on the line, has the code
42def used(gs: List<&2, F.Graded>, +path: String, +line: U32, +code: String) -> Bool:
43 match gs:
44 case Nil{}:
45 False{}
46 case Con{F.Graded{_ll, F.Finding{p, l, _col, _len, rule, _msg}}, rest}:
47 Lazy.or_else(
48 Lazy.and_then(String.eq(p, path),
49 _u => Lazy.and_then(U32.is_eq(l, line), _v => String.eq(Codes.code(rule), code))),
50 _w => used(rest, path, line, code))
51
52# what a bare mark is told
53def say.bare() -> String:
54 "`# noqa` names no code, so it silences nothing; name the codes, e.g. `# noqa: L001`."
55
56# what an unused code is told: a rule's, or no rule's
57def say(+code: String) -> String:
58 Bool.pick(String, known(code), "`# noqa: " ++ code ++ "` silences nothing on this line.",
59 "`# noqa: " ++ code ++ "` is no rule's code, so it silences nothing.")
60
61# one finding for each code judged here that silences nothing on its line
62def check.codes(
63 cs: List<&2, String>,
64 +whole: Bool,
65 +path: String,
66 +line: U32,
67 +col: U32,
68 +len: U32,
69 +gs: List<&2, F.Graded>
70) -> List<&2, F.Finding>:
71 match cs:
72 case Nil{}:
73 Nil{}
74 case Con{+c, rest}:
75 +more = check.codes(rest, whole, path, line, col, len, gs)
76 +bad = Lazy.and_then(judged(whole, c), _u => Bool.not(used(gs, path, line, c)))
77 +msg = say(c)
78 Bool.pick(List<&2, F.Finding>, bad, F.Finding{path, line, col, len, "noqa", msg} <> more, more)
79
80# a mark's findings: one when it is bare, else one per code that silences
81# nothing
82def check.mark(mk: Noqa.Mark, +whole: Bool, +path: String, +gs: List<&2, F.Graded>) -> List<&2, F.Finding>:
83 match mk:
84 case Noqa.Mark{line, col, len, Nil{}}:
85 [F.Finding{path, line, col, len, "noqa", say.bare()}]
86 case Noqa.Mark{line, col, len, Con{c, rest}}:
87 check.codes(c <> rest, whole, path, line, col, len, gs)
88
89# every mark of the file at the path, against the run's graded findings
90def check(mks: List<&2, Noqa.Mark>, +whole: Bool, +path: String, +gs: List<&2, F.Graded>) -> List<&2, F.Finding>:
91 match mks:
92 case Nil{}:
93 Nil{}
94 case Con{mk, rest}:
95 List.append(&2, F.Finding, check.mark(mk, whole, path, gs), check(rest, whole, path, gs))