src/lint/plan.bend checks
raw source on the hub · import 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/plan.bend as Plan
src/lint/plan: bolt (the lint) as a pure planner. It reads a World
(src/lint/world.bend) and returns either the questions it still needs
answered (wants) or the Plan: the lines to print and the exit status
(plan). The interpreter (src/lint.bend) loops on wants, answering each
question by IO, until nothing is wanted, then prints plan's lines and
exits with its status. The design is docs/rfc/bolt-lint-planner.md.
With no files named, the planner walks the tree under . as a fold over the
World's listings: a directory not listed yet reads as empty and is asked
for, so each round of the loop lists one more level of the tree. Once every
directory the walk reads is listed, it asks for the text of each source, of
SPEC.md, and of every bolt.bend candidate of their directories, each once.
A directory's candidates are taken once it is resolved against the World's
working directory (Config.home), so a relative path is graded by the same
bolt.bend wherever bolt runs from.
wants never parses a file; plan parses and lints once. Once every rule
has run and each finding is graded, the noqa comments (src/noqa.bend)
silence what they name, and then the noqa rule reports the comments that
silenced nothing.
9 imports
import Base import ../lazy/lazy.bend as Lazy import ./world.bend as W import ../finding.bend as F import ../src.bend as Src import ../rules.bend as Rules import ../config.bend as Config import ../noqa.bend as Noqa import ../rules/style/noqa.bend as NoqaRule
Types
type Plan source · line 31 · raw
Data
what bolt prints, in order, and the status it exits with
Plan@lines:List<&2, String> -> @exit:U32 -> Plan
type Walk source · line 84 · raw
Data
a walk once it stops: the .bend files it found, and every directory it
read, the last one read first
Walk@found:List<&2, String> -> @read:List<&2, String> -> Walk
type Got source · line 279 · raw
Data
a source path and the text the World holds for it
Got@path:String -> @text:Maybe<&2, String> -> Got
type Conf source · line 335 · raw
Data
a directory and the config its findings are graded by
Conf@dir:String -> @config:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/config.Config -> Conf
Definitions
def lines.of source · line 35 · raw
@pl:Plan -> List<&2, String>
the lines a plan prints
def exit.of source · line 40 · raw
@pl:Plan -> U32
the status a plan exits with
def walk.skipped source · line 52 · raw
@+name:String -> Bool
a directory the walk never descends into
def walk.bare source · line 56 · raw
@+name:String -> String
an entry's name without the "/" that marks it a directory
def walk.under source · line 60 · raw
@+dir:String -> @+name:String -> String
a name directly under a directory, as a path
def walk.dirs source · line 64 · raw
@es:List<&2, String> -> @+dir:String -> List<&2, String>
the sub-directories of a listing worth descending into, as paths
def walk.bends source · line 74 · raw
@es:List<&2, String> -> @+dir:String -> List<&2, String>
the .bend files of a listing, as paths (a directory's name ends in "/")
def walk.found source · line 88 · raw
@wk:Walk -> List<&2, String>
the files a walk found
def walk.read source · line 93 · raw
@wk:Walk -> List<&2, String>
the directories a walk read, in the order it read them
def walk source · line 101 · raw
@fuel:Nat -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> @queue:List<&2, String> -> @acc:List<&2, String> -> @seen:List<&2, String> -> Walk
every .bend file under the directories still queued, the fuel bounding how
many directories are read, each read through the World's listing. What is
found is put in front of what came before, not after it, so the walk stays
linear; files sorts at the end regardless.
def limit source · line 125 · raw
Nat
how many directories the walk reads at most; past it the walk stops,
silently. A literal, not U32.to_nat(100000): the checker keeps a literal
whole and steps it one at a time, so BOLT-SCOPE-1's law can name the bound,
where it would expand the call in unary and overflow. The compiler emits
the same U32.to_nat for either.
def tree source · line 129 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> Walk
the walk of the tree under ., reading at most limit() directories
def files.named source · line 136 · raw
@paths:List<&2, String> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, String>
the files named, or every .bend file the walk finds when none were
def files source · line 145 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, String>
the files the lint runs over
def is_config source · line 149 · raw
@+pp:String -> Bool
a bolt.bend is configuration, not source
def sources source · line 153 · raw
@ps:List<&2, String> -> List<&2, String>
the paths that are source
def inputs source · line 162 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, String>
the source files of the run, in file-list order
def seen.has source · line 169 · raw
@ps:List<&2, String> -> @+pp:String -> Bool
whether a path is among the paths
def uniq source · line 177 · raw
@ps:List<&2, String> -> @+seen:List<&2, String> -> List<&2, String>
each path once, where it first appears
def dirs.of source · line 187 · raw
@ps:List<&2, String> -> List<&2, String>
the directory of each path
def conf.dirs source · line 196 · raw
@+ps:List<&2, String> -> List<&2, String>
the directory of every source and of SPEC.md, each once: every finding's path is a source's or SPEC.md, so these are the directories grading needs
def conf.chain source · line 202 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> @dir:String -> List<&2, String>
the bolt.bend candidates of a directory as a path names it, nearest first: the directory resolved against the working directory, then each parent up to the root
def conf.cands source · line 206 · raw
@ds:List<&2, String> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, String>
the bolt.bend candidates of each directory, nearest first
def asks.entries source · line 214 · raw
@ds:List<&2, String> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
the listing of each directory, as a question
def asks.texts source · line 222 · raw
@ps:List<&2, String> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
the text of each path, as a question
def lists.named source · line 231 · raw
@paths:List<&2, String> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
the directories the walk lists: every one it reads, none when files were named
def lists source · line 239 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
the listings the plan reads
def texts source · line 244 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
the texts the plan reads: each source, SPEC.md, and every bolt.bend candidate of their directories, each once
def looks source · line 250 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
every question the plan reads the World through: the listings, then the texts
def unanswered source · line 254 · raw
@asks:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
the questions a World does not answer yet
def wants.pick source · line 263 · raw
@ls:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
the listings still open, or, once there are none, the texts still open
def wants source · line 272 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.Ask>
the questions a World still leaves open. The file list is known only once every directory the walk reads is listed, so the texts wait for the walk.
def gots source · line 283 · raw
@ps:List<&2, String> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, Got>
each source with what the World answers for it
def unread source · line 291 · raw
@gs:List<&2, Got> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>
one finding for each source that could not be read
def srcs_of source · line 301 · raw
@gs:List<&2, Got> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/src.Src>
every source that was read, parsed once for every rule
def per_file source · line 311 · raw
@ss:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/src.Src> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>
every source's findings from the per-file rules
def found.at source · line 322 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> @+gs:List<&2, Got> -> @+ss:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/src.Src> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>
every finding of every rule, ungraded, from the sources and what the World answers for them: the read failures, the per-file findings of each source, then the project rules' over every source, told whether the run is the whole tree, and SPEC.md's text
def found source · line 327 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>
every finding of every rule, ungraded
def texts.at source · line 339 · raw
@ps:List<&2, String> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, Maybe<&2, String>>
what the World holds at each path
def conf.near source · line 348 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> @dir:String -> 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/config.Config
a directory's config: the nearest bolt.bend the World could read among its candidates, or the defaults
def confs.at source · line 352 · raw
@ds:List<&2, String> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, Conf>
each directory's config
def confs source · line 360 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, Conf>
the config of every directory grading needs
def conf.find source · line 366 · raw
@cs:List<&2, Conf> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> @+dir:String -> 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/config.Config
the config of a directory, from the table; one the table does not hold is worked out the same way (every finding's directory is in the table, so this never happens in a run)
def config.at source · line 374 · raw
@+cs:List<&2, Conf> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> @path:String -> 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/config.Config
the config a finding at a path is graded by: its directory's
def grade source · line 379 · raw
@+cs:List<&2, Conf> -> @+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> @fs:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded>
every finding graded by the config of its directory, in order, the ones at off dropped
def noqa source · line 392 · raw
@ms:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/noqa.Marks> -> @+whole:Bool -> @+gs:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding>
the noqa rule's findings on each file's marks, against the graded
findings, each put at its file as a per-file rule's are
def after source · line 401 · raw
@+ms:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/noqa.Marks> -> @+whole:Bool -> @+gs:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded> -> @grader:(@_:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Finding> -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded>) -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded>
the graded findings no mark silences, in order, then the noqa rule's,
graded by the grader given: nothing silences what noqa reports
def final source · line 412 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded>
every finding of the run, graded, then silenced by the marks of the
sources, then noqa's own, which judges a project rule's code only when
the run is the whole tree. The sources are parsed once for both.
def errors.at source · line 423 · raw
@ll:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/config.Level -> @more:U32 -> U32
one more at error, or the count as it was
def errors source · line 433 · raw
@gs:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded> -> U32
how many are errors
def warnings.at source · line 441 · raw
@ll:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/config.Level -> @more:U32 -> U32
one more below error, or the count as it was
def warnings source · line 451 · raw
@gs:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded> -> U32
how many are not errors
def has_error source · line 459 · raw
@gs:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded> -> Bool
whether any is an error
def count source · line 468 · raw
@+nn:U32 -> @+what:String -> String
1 error, 2 errors
def summary source · line 472 · raw
@+gs:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded> -> String
clean, or the counts
def show_all source · line 477 · raw
@gs:List<&2, 0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/finding.Graded> -> List<&2, String>
every graded finding as a line
def plan source · line 486 · raw
@+world:0x582b4b0fdf3dafdeecc8c3bfddc5e4db/src/lint/world.World -> Plan
bolt over a World: every graded finding no mark silences as a line, then
noqa's, then the summary of those, and exit 1 exactly when one is an error