~/bend-docscommunity

src/lint/plan.bend checks

raw source on the hub · import 0xd96f2ab40f5df4925c42e96d0ba857ff/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

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

type Got source · line 279 · raw

Data

a source path and the text the World holds for it

type Conf source · line 335 · raw

Data

a directory and the config its findings are graded by

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:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.Ask>

the text of each path, as a question

def lists.named source · line 231 · raw

@paths:List<&2, String> -> @+world:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.Ask>

the listings the plan reads

def texts source · line 244 · raw

@+world:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.Ask> -> @+world:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.Ask>

the questions a World does not answer yet

def wants.pick source · line 263 · raw

@ls:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.Ask> -> @+world:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.Ask>

the listings still open, or, once there are none, the texts still open

def wants source · line 272 · raw

@+world:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/src.Src>

every source that was read, parsed once for every rule

def per_file source · line 311 · raw

@ss:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/src.Src> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding>

every source's findings from the per-file rules

def found.at source · line 322 · raw

@+world:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> @+gs:List<&2, Got> -> @+ss:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/src.Src> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding>

every finding of every rule, ungraded

def texts.at source · line 339 · raw

@ps:List<&2, String> -> @+world:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, Maybe<&2, String>>

what the World holds at each path

def conf.near source · line 348 · raw

@+world:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> @dir:String -> 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, Conf>

each directory's config

def confs source · line 360 · raw

@+world:0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> @+dir:String -> 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> @path:String -> 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> @fs:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/noqa.Marks> -> @+whole:Bool -> @+gs:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Graded> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/noqa.Marks> -> @+whole:Bool -> @+gs:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Graded> -> @grader:(@_:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Finding> -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Graded>) -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/src/lint/world.World -> List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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:0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Graded> -> U32

how many are errors

def warnings.at source · line 441 · raw

@ll:0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Graded> -> U32

how many are not errors

def has_error source · line 459 · raw

@gs:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/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, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Graded> -> String

clean, or the counts

def show_all source · line 477 · raw

@gs:List<&2, 0xd96f2ab40f5df4925c42e96d0ba857ff/src/finding.Graded> -> List<&2, String>

every graded finding as a line

def plan source · line 486 · raw

@+world:0xd96f2ab40f5df4925c42e96d0ba857ff/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