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. 13 import Base 14 import ../../lazy/lazy.bend as Lazy 15 import ../../finding.bend as F 16 import ../../codes.bend as Codes 17 import ../../noqa.bend as Noqa 18 19 # a project rule's code 20 def 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 26 def 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 30 def 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 38 def known(+code: String) -> Bool: 39 known.in(Codes.table(), code) 40 41 # a graded finding at the path, on the line, has the code 42 def 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 53 def 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 57 def 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 62 def 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 82 def 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 90 def 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))