Linting¶
The ubCode language server has a linting feature built in and detects a broad range of RST issues. The linting feature is enabled by default. Specific rules can be deactivated in the ubproject.toml file.
Lint errors appear in the editor as well as in the problems tab. The same rules also run on the command line through ubc check, the canonical project linter for CI and pre-commit use.
Supported lint rules:
Identifier |
Description |
|---|---|
|
Warns on tabs in a line, which can degrade performance of source mapping. |
|
Warns on missing blank lines between syntax blocks. |
|
Warns on issues with title under/over lines. |
|
Warns on unexpected titles in a context where they are not allowed. |
|
Warns on unexpected indentation of a paragraph line. |
|
Warns on literal blocks with no content. |
|
Warns on malformed hyperlink targets. |
|
Warns on malformed substitution definition. |
|
Warns on malformed tables. |
|
Warns on inconsistent title levels, e.g. a level 1 title style followed by a level 3 style. |
|
Warns on unknown directives. |
|
Warns if the second line of a directive starts with an indented |
|
Warns on malformed directives. |
|
Warns on directives with missing required content. |
|
Warns on a directive given a body when its definition permits none
(for example |
|
Warns on directives with a missing required argument. |
|
Warns on inline markup with no closing marker. |
|
Warns on malformed inline roles. |
The rules above are reported by the reStructuredText parser.
The Markdown parser reports its own, smaller set of parse-level codes,
named without the block. prefix
because Markdown directives are fences rather than explicit-markup blocks:
Identifier |
Description |
|---|---|
|
Warns on unknown directives. |
|
Warns on a directive whose option block cannot be read
(invalid YAML, or a malformed |
|
Warns on directives with missing required content. |
|
Warns on a directive given a fence body when its definition permits none
(for example |
|
Warns on directives with a missing required argument. |
Markup-semantics diagnostics¶
Added in version 0.31.0.
In addition to the parse-level rules above,
ubCode analyses the meaning of the parsed markup
(directive options, diagram directives, document structure)
and reports the issues it finds.
Most apply to reStructuredText and Markdown documents alike —
a row says so when it does not —
and they are reported in the editor, by ubc check,
and in the ubc build diagnostics log.
The rules in this table are warnings unless a row says otherwise.
Their source label is ubcode-markup for most rules
and ubcode-syntax for some,
so an editor filter on the source column should include both.
Identifier |
Description |
|---|---|
|
Warns when a directive option value cannot be interpreted as its declared type. |
|
Warns when a directive option value is outside its declared set of choices
(e.g. |
|
Warns when a diagram directive (e.g. |
|
Warns when a |
|
Warns when a |
|
Warns when a |
|
Warns when an |
|
Warns when an |
|
Warns when the element an |
|
Warns when a |
|
Warns when a |
|
Warns when a |
|
Warns when directives are nested more than 64 levels deep.
Reported once per crossing point — the first directive past the cap —
so two over-deep chains side by side warn twice, and a single chain
300 levels deep still warns once.
That directive and everything inside it render as plain directive blocks
instead of being interpreted.
Their own body still renders;
a directive that pulls in or generates content (for example |
|
Warns on non-consecutive Markdown heading levels,
e.g. a |
|
Notes that a cross-reference role ( |
|
Warns when a |
|
Warns when an |
|
Warns when a |
|
Warns when a |
|
Warns when a |
|
Warns when an |
|
Warns when a |
|
Warns when a Markdown document’s YAML front matter cannot be parsed. The front matter is ignored and the document still builds. |
|
Warns when a Markdown document’s YAML front matter parses but is not a mapping of keys to values (a bare list or scalar). The front matter is ignored and the document still builds. |
|
Warns when a document’s |
|
Warns when a MyST attribute group gives a value
the key cannot read — an image |
|
Warns when a MyST attribute group gives a value
outside the key’s fixed set — an image |
|
Warns when a block attribute group has no block below it to attach to (the end of the file, or the end of a list item or block quote). The group is ignored, as it is in MyST, which says nothing. |
|
Warns when the element below a block attribute group cannot carry
attributes at all — a comment, a target, a block break, a thematic
break, an HTML block, a math block, a footnote definition or an
|
|
Informational. Reports a key the element it landed on does not
support — |
These codes are governed by the same lint configuration
as every other rule:
ignore, per-file-ignores, message-ignores,
and the --extend-ignore flag of ubc check all apply.
Toctree diagnostics¶
Added in version 0.31.0.
ubCode expands the project’s toctree directives into a single navigation tree,
rooted at the configured root document,
and reports the structural problems it finds along the way.
These are project-level diagnostics — they depend on which documents exist
and how the toctrees reference one another —
and surface in the editor, by ubc check,
and in the ubc build diagnostics log.
Identifier |
Description |
|---|---|
|
Warns when a toctree entry references a document that does not exist (including an entry that names its own containing document). |
|
Warns when a document is listed more than once within a single toctree; the duplicate entry is kept. |
|
Warns when a circular toctree reference is detected and pruned. |
|
Warns when a toctree |
|
Warns when a document is not reachable from any toctree;
the root document and documents pulled in via |
|
Notes that a document is referenced from more than one toctree — an informational message, not a warning. |
|
Warns when the configured root document ( |
|
Notes that a toctree entry names a document this variant’s source rules removed — an informational message, not a warning, and the message names the rule that removed it. |
|
Warns when a toctree entry names a document that has no title and holds no toctree of its own. Such an entry generates no link, exactly as in a Sphinx build, and the document keeps its place in the previous/next chain. Silencing the warning does not restore the link. |
Like every other rule, these codes are governed by the
lint configuration
(ignore, per-file-ignores, message-ignores,
and the --extend-ignore flag of ubc check).
Imported-needs diagnostics¶
Everything a .. needimport:: reports is anchored at the directive and
governed by the lint configuration.
Most of it arrives under one umbrella code;
three causes have their own, so they can be graded and silenced
independently of genuine read failures.
Identifier |
Description |
|---|---|
|
The umbrella code: a source that could not be read or parsed, a need that could not be built, and every construct refused inside imported content (see What works inside imported need content). |
|
Notes that a |
|
Warns that an |
|
Warns that two or more configured parsers claim an imported need’s |
Because a bare code in ignore matches exactly
(see Code matching and .* wildcards),
ignore = ["needs.import"] silences the umbrella code only —
it does not reach the three codes above,
and silencing any of those does not hide a source that failed to read.
To silence the umbrella and all three at once,
use the family wildcard ignore = ["needs.import.*"].
Codelinks diagnostics¶
Added in version 0.29.0.
In addition to RST linting,
ubCode validates codelinks one-line markers in source files
(C/C++, Python, Rust, C#, YAML).
When a file belongs to a codelinks project,
marker syntax issues are reported as warnings with the source label ubcode-codelinks.
See Tracing source code with Codelinks for the full list of warning codes and details.
Linting on the command line¶
Added in version 0.31.0.
The ubc check command is the canonical project linter,
in the mould of ruff check and cargo check.
It reports the same project-wide diagnostics the editor shows,
so a passing ubc check and a clean Problems view mean the same thing.
There are three scopes:
ubc check(no paths) checks the whole project, discovered by walking up from the current directory to the nearestubproject.toml. Every diagnostic family runs — the parse, markup-semantics, toctree, reference, need, and schema families above — and both reStructuredText and Markdown documents are included.ubc check <paths>still resolves the whole project, so cross-file diagnostics such as duplicate need IDs and broken references stay correct, but reports only the diagnostics located under the named paths. Project-level configuration problems are always reported, whatever the paths.ubc check --per-file <paths>is the fast, project-free path: each named file is parsed in isolation, so only the per-file (parse and markup) families run — no cross-file, reference, toctree, or schema checks — and non-RST files such as Markdown are skipped.
Cache.
The whole-project and scoped modes read and warm the on-disk .ub_cache,
exactly like ubc build index, so repeated runs are fast;
pass --no-cache for a run that neither reads nor writes it.
--per-file never touches the cache.
Scoped details.
A named path that does not exist on disk is an error,
so a typo in a CI recipe fails rather than passing green;
a path that exists but matches no source file is a warning on stderr.
Configuration-less files that span unrelated directory trees are refused
(use --per-file instead of walking the whole disk).
Exit policy.
By default any warning-or-worse finding fails the command (exit 1);
info-level findings alone do not.
--deny <none|info|warning|error> moves the failure threshold
(none never fails the threshold),
and --max-warnings <N> caps the number of warnings —
when both are given the stricter one wins.
ubc build html applies the same policy over both of its warning
streams, and can declare the threshold in configuration —
see Building for production.
An invalid flag value is a usage error (exit 2).
License.
Like ubc build index, ubc check runs without a license on small
projects (up to five files) and fails with an error above that;
--per-file requires an active license for any non-open-source project.
Human output.
Each finding prints as a block headed by its severity and its code —
error[needs.schema_definition_violation],
warning[image.not_found],
info[toctree.multiple_toc_parents] —
followed by its source locations and its message.
The label is plain text, so it survives a pipe, a CI log and a file:
grep '^warning\[' over a captured run lists every warning.
On a terminal the header is coloured by severity,
red for errors and yellow for warnings,
and an informational block is dimmed throughout;
when the output is piped or redirected
(unless colour is explicitly forced),
or NO_COLOR is set to a non-empty value,
the escapes are omitted and the words remain.
The same block is printed by ubc build index, ubc build html
and ubc build linkcheck,
so one finding reads the same way whichever command reports it.
While it works.
Every command that indexes a project for a person —
ubc check, every ubc build, ubc report, ubc schema and ubc diff —
says what it is about to do —
Building index for: <config> and, when there is anything to parse,
Processing N files —
and then, on a terminal, shows one progress bar redrawn in place until the pass ends:
indexing 412/1001 [████████░░░░░░░░░░░░] 4s
The count is the files being parsed this run, not the project’s file count:
a warm run reuses everything that has not changed,
so a project of a thousand files with one edit reports Processing 1 file and finishes at 1/1.
The bar is cleared the moment the last file is parsed,
so every line the run prints afterwards — the remaining pipeline lines, the findings, the summary —
starts on a clean row;
on ubc build html the build’s own bars come next, and each of those is cleared the same way.
It is written only when standard error is a terminal:
a pipe, a file or a CI log gets the opening lines and then nothing until the result,
so a captured log stays greppable and carries no carriage returns.
Setting CI suppresses it even on a runner that allocates a terminal,
as do TERM=dumb, an unset TERM and --quiet.
--verbose replaces it with one parsed <path> line per file as each is parsed —
the line and the bar are mutually exclusive,
since both want the same row.
ubc build html shows one more bar for each of the build’s three main phases:
rendering the pages, assembling them into the site, and finishing with the assets.
rendering 412/1001 [████████░░░░░░░░░░░░] 4s
They appear in that order, each cleared before the next one opens,
and the last cleared before the build’s summary line —
so a build that used to spend seconds saying nothing now says which phase it is in and how far through.
Every rule above applies unchanged:
a terminal only, nothing under --quiet, CI, TERM=dumb or an unset TERM,
and under --verbose the Timings: line reports each phase’s duration instead.
Machine-readable output.
--output-format json writes a single JSON document to stdout —
the diagnostics and a summary severity tally —
with every other line on stderr, so stdout is safe to pipe into a JSON consumer:
$ ubc check --output-format json
{
"diagnostics": [
{
"code": "image.not_found",
"severity": "warning",
"message": "Image file not found: 'missing.png'",
"sources": [
{"stype": "local", "path": "index.rst", "line": 4, "column": 12, "label": null}
]
}
],
"summary": {"errors": 0, "warnings": 1, "infos": 0}
}
The item shape matches the editor’s project-wide diagnostics
(code, message, and a sources list tagged by stype),
with a severity field added.
The exit code and the --deny / --max-warnings policy are unchanged by the format.