Guide

Check a document with lint

Find text that overflows its column, squeezed columns, missing glyphs, lonely headings, split rows and markup in text fields, as text or JSON.

On this page

Community

brevier lint renders a template and checks the pages, not the source. It lists every problem with its page and the line of the generated HTML that caused it. It writes no PDF.

brevier lint rechnung.html --data rechnung.json --debug-dir out/
rechnung.html
  page 1    table     column "Stk" squeezed below its minimum width (10.0 < 15.0 mm)  → out/rechnung.debug.html:9
  → 1 problem. exit code 1
debug file: out/rechnung.debug.html (holds the document's data)

Exit code 0 means no problems. Exit code 1 means at least one problem. Run it in your build to stop a bad document before a customer sees it. All options are on the CLI reference.

What lint reports

Kind Meaning
overflow Text wider than its table column or its box. The message names the column header, the first 20 characters and both widths in mm.
table A table column narrower than its declared minimum width. See below.
glyph A character that the font does not draw, or that a fallback font draws instead of the font you asked for.
orphan A heading alone at the bottom of a page. A heading at the end of the last page is not reported.
split A table row broken across two pages. The message names the row number and the pages.
hyphens More than 3 hyphenated lines in a row, or one before a page break.
data A value in your data that does not fit its field type: markup or a line break in a text field. See Check the data.

Check the data

A problem can be in the data and not in the layout. A text field removes line breaks and prints markup as plain text: the value Zeile 1<br/>Zeile 2 prints the characters <br/> on the page. Lint finds this before the PDF is made.

The check runs when you pass --data and a schema is found. The schema is <name>.schema.json next to the template, or the one you name with --schema. A field has the type text when its schema has "x-brevier-type": "text" or no x-brevier-type. A field that the schema does not list counts as text.

rechnung.schema.json
{
  "type": "object",
  "properties": {
    "rechnung": {
      "type": "object",
      "properties": {
        "nummer": { "type": "string" },
        "bemerkung": { "type": "string", "x-brevier-type": "text" },
        "lieferhinweis": { "type": "string", "x-brevier-type": "multiline" }
      }
    }
  }
}

Take a rechnung.json with 5 records. Three records have <br/> in bemerkung, and one has a line break in it. All 5 records have a line break in lieferhinweis.

brevier lint rechnung.html --data rechnung.json
rechnung.html
  document  data      rechnung.bemerkung contains markup (3 of 5 records): suggest `multiline` or `rich`
  document  data      rechnung.bemerkung contains newlines (1 of 5 records): suggest `multiline`
  → 2 problems. exit code 1
debug file: rechnung.debug.html (holds the document's data)
  • Lint reports one line for each field and problem, with the number of records that have it. The path starts at the root of the record, so kunde.name and lieferant.name are two fields with two types.
  • lieferhinweis is not reported: a multiline field keeps line breaks. A rich field keeps markup.
  • Markup means an HTML tag such as <br/>, <b> or </p>. The text Preis < 5 und > 3 is not markup.
  • The messages never contain the values of your data.
  • The data findings have no page and no line: the cause is in the data, not in the generated HTML.

The fix is in the schema or in the data. Declare multiline or rich for a field that should keep line breaks or markup, or clean the value in your application. See Field types.

Situation What lint does
--data and a schema Checks the data.
--data and no schema Skips the data check and prints No schema for rechnung.html: data checks skipped on standard error. This is not a problem: the exit code does not change.
--schema false Skips the data check.
A schema file that is missing or not valid JSON Stops with an error and exit code 1.

Read the output as JSON

--format json prints an array with one object for each problem and [] when there is none. Each object has the keys page, kind, message, file and line. Use it to feed another tool.

brevier lint rechnung.html --data rechnung.json --format json
[
  {
    "page": null,
    "kind": "data",
    "message": "rechnung.bemerkung contains markup (3 of 5 records): suggest `multiline` or `rich`",
    "file": null,
    "line": null
  },
  {
    "page": null,
    "kind": "data",
    "message": "rechnung.bemerkung contains newlines (1 of 5 records): suggest `multiline`",
    "file": null,
    "line": null
  }
]

page, file and line are null for a problem that has no place in the generated HTML.

Declare a minimum column width

A table column has no minimum width by default, so lint never reports a squeezed column on its own. You declare the minimum on the <col> of the column, with the attribute data-min-width:

<table>
  <col style="width: 40mm">
  <col style="width: 25mm" data-min-width="20mm">
  <tr><th>Position</th><th>Menge</th></tr>
</table>

CSS min-width does not work on a column, so Brevier reads this attribute instead.

  • The value is a number followed by mm: 20mm or 22.5mm. Any other value is ignored.
  • Lint compares the width of the column on the page with the minimum. It reports the column when it is narrower by more than 0.3 mm.
  • A column without the attribute is never reported.
  • The attribute changes nothing in the PDF. Only brevier lint reads it.

Run lint in CI

Run brevier lint in your build pipeline to catch layout problems before generating PDFs for customers.

Licence key and network

Like brevier pdf, brevier lint needs a licence key in the environment variable BREVIER_LICENCE_KEY. Store your licence key in your CI platform's secrets settings.

Linting needs no network access. It runs completely offline.

Debug HTML warning

brevier lint writes a debug HTML file (such as rechnung.debug.html or in --debug-dir) to show line numbers for reported problems. This file contains the document's rendered data.

Do not save or publish the debug HTML file as a public CI artifact, because it contains the document's data.

GitHub Actions

This workflow installs Brevier with pip and lints a template on every push and pull request. Add your licence key as the repository secret BREVIER_LICENCE_KEY.

.github/workflows/lint-templates.yml
name: lint templates
on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.13"
      - name: Install Pango and brevier
        run: |
          sudo apt-get update -qq
          sudo apt-get install -y libpango-1.0-0 libpangoft2-1.0-0
          pip install brevier
      - name: Lint the templates
        env:
          BREVIER_LICENCE_KEY: ${{ secrets.BREVIER_LICENCE_KEY }}
        run: brevier lint templates/rechnung.html --data templates/rechnung.json

A finding gives exit code 1, so the job fails and the pull request shows it.