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

source.tab_in_line

Warns on tabs in a line, which can degrade performance of source mapping.

block.blank_line

Warns on missing blank lines between syntax blocks.

block.title_line

Warns on issues with title under/over lines.

block.title_disallowed

Warns on unexpected titles in a context where they are not allowed.

block.paragraph_indentation

Warns on unexpected indentation of a paragraph line.

block.literal_no_content

Warns on literal blocks with no content.

block.target_malformed

Warns on malformed hyperlink targets.

block.substitution_malformed

Warns on malformed substitution definition.

block.table_malformed

Warns on malformed tables.

block.inconsistent_title_level

Warns on inconsistent title levels, e.g. a level 1 title style followed by a level 3 style.

block.directive_unknown

Warns on unknown directives.

block.directive_indented_options

Warns if the second line of a directive starts with an indented :.

block.directive_malformed

Warns on malformed directives.

block.directive_no_content

Warns on directives with missing required content.

block.directive_no_argument

Warns on directives with a missing required argument.

inline.no_closing_marker

Warns on inline markup with no closing marker.

inline.role_malformed

Warns on malformed inline roles.

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 issues as warnings with the source label ubcode-markup. These apply to reStructuredText and Markdown documents alike, and are reported in the editor, by ubc check, and in the ubc build diagnostics log.

Identifier

Description

directive.invalid_option_value

Warns when a directive option value cannot be interpreted as its declared type.

directive.invalid_option_choice

Warns when a directive option value is outside its declared set of choices (e.g. :align: on an image).

directive.diagram_content_and_file

Warns when a diagram directive (e.g. mermaid) has both inline content and a file argument; the file argument is ignored.

directive.unknown_role

Warns when a default-role directive names an unknown interpreted text role (the default role is left unchanged, as in docutils).

directive.invalid_role

Warns when a role directive’s arguments are not valid role names, or its base role (.. role:: name(base)) is unknown — the role is not defined.

directive.role_redefinition

Warns when a role directive redefines a role already defined earlier in the same document (the last definition wins, as in docutils).

directive.replace_single_paragraph

Warns when a replace substitution body is not a single paragraph (the definition is left empty, as in docutils).

directive.invalid_character_code

Warns when a unicode substitution code point is out of range (the definition is left empty, as in docutils).

directive.invalid_date_format

Warns when a date substitution format string cannot be interpreted.

heading.inconsistent_level

Warns on non-consecutive Markdown heading levels, e.g. a # heading followed by ### (all Markdown flavours).

role.invalid_pep_number

Warns when a :pep: role’s number is not a value from 0 to 9999.

role.invalid_rfc_number

Warns when an :rfc: role’s number is not a value greater than or equal to 1.

needs.variant

Warns when a :variant: role cannot be resolved, because no variant data is configured or the expression does not resolve.

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

toctree.nonexisting_document

Warns when a toctree entry references a document that does not exist (including an entry that names its own containing document).

toctree.duplicate_entry

Warns when a document is listed more than once within a single toctree; the duplicate entry is kept.

toctree.circular

Warns when a circular toctree reference is detected and pruned.

toctree.empty_glob

Warns when a toctree :glob: pattern matches no documents.

toctree.not_included

Warns when a document is not reachable from any toctree; the root document and documents pulled in via include are exempt.

toctree.multiple_toc_parents

Notes that a document is referenced from more than one toctree — an informational message, not a warning.

toctree.missing_root_document

Warns when the configured root document ([project].root_doc) does not exist.

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).

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 nearest ubproject.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 <info|warning|error> moves the failure threshold, and --max-warnings <N> caps the number of warnings — when both are given the stricter one wins. 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.

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.