Reports
The lineage report family accepts selector and optional direction and level variables and is available as HTML, CSV, Markdown, text, XLSX and PDF.
bluep report renders text from the model through a small template language. Seven templates are built
in (CSV, Markdown and HTML); custom templates are plain files. Output is deterministic: no timestamps, no
absolute paths, no environment values.
Command line
bluep report <dir> --template <name> [--format html|csv|md|txt] [--out <file>] [--var k=v]...
bluep report <dir> --template-file <path> [--format html|csv|md|txt] [--out <file>] [--var k=v]...
bluep report --list
--templatenames a built-in (see--list);--template-filereads a custom template.- The output format decides the automatic escaping (below). It defaults from the extension of the
template name (
.html/.htm,.csv,.md/.markdown,.txt), otherwisetxt. --outwrites the result to a file instead of standard output.--var k=vdefines a string variable available asvars.k(repeatable).- Exit codes: 0 success, 2 usage error, 3 template error or model error. Template errors are reported
as
<template>:<line>:<column>: <message>.
Built-in templates
| name | format | content |
|---|---|---|
classification.html |
html | matrix of classification levels with the entities and attributes at each level |
columns.csv |
csv | one row per physical column: target, schema, table, type, nullability, default, mapping, classifications |
dictionary.md |
md | data dictionary with one section per entity: attributes, primary and unique keys |
entities.csv |
csv | one row per entity: name, description, attribute count, stereotype, subject areas |
glossary.md |
md | glossary terms with definitions, aliases and the entities and attributes using them |
lint.md |
md | lint findings grouped by rule |
relationships.md |
md | relationships with columns, cardinalities and referential actions |
Their sources live in crates/bluep-core/templates/ and are good starting points for custom templates.
Template language
A template is text with two kinds of markers:
{{ expression }}prints a value;{% statement %}controls the flow:for,endfor,if,elif,else,endif,set.
A - directly inside a marker trims whitespace next to it: {{- and {%- remove spaces and tabs and at
most one newline before the marker; -}} and -%} remove spaces and tabs and at most one newline after
it. Putting a statement on its own line and ending it with -%} makes the whole line disappear from the
output.
There is no comment syntax. To print a literal {{, write {{ "{{" }}.
Statements
{% for item in model.relationships %}...{% endfor %} iterate the values of an object (sorted keys) or an array
{% for name, entity in model.entities %}...{% endfor %} also bind the key (object) or the 0-based index (array)
{% if expr %}...{% elif expr %}...{% else %}...{% endif %}
{% set total = total + 1 %} assign a variable; persists after loops end
Inside a loop, loop.index (1-based), loop.first, loop.last and loop.length are available. Looping
over null (for example a missing optional key) produces no iterations. Loop variables shadow outer
variables and are restored when the loop ends.
Expressions
- Literals:
'text'or"text"(escapes\\,\',\",\n), integers,true,false,null. - Paths:
model.entities.customer.attributes[0].name,vars.owner,items.length. A missing nested key yieldsnull; a missing top-level variable is an error. - Operators, from loosest to tightest:
or,and,not, comparisons (== != < <= > >=),+and-.+concatenates two strings or adds two integers.<and friends compare two integers numerically or two strings byte-wise; anything else is an error.==compares structurally. - Truthiness:
false,null,0,"", empty arrays and empty objects are false. - Function calls:
len(x),join(list, ", "), ... - Filters:
{{ value | upper | truncate(20) }}—x | f(a, b)isf(x, a, b).
Functions
| function | result |
|---|---|
len(x) |
number of elements, keys or characters; 0 for null |
keys(obj) / values(obj) |
the keys / values of an object as arrays |
sorted(arr) |
strings sorted byte-wise, or objects sorted by their name |
sort_by(arr, key) |
stable sort of objects by a key |
join(arr, sep) |
elements joined by sep |
default(x, d) |
d when x is null, else x |
contains(c, x) |
element of an array, substring of a string, or key of an object |
has(obj, key) |
object has the key |
lower(s), upper(s), trim(s) |
string operations |
replace(s, a, b), split(s, sep) |
string operations |
snake(s), pascal(s), camel(s) |
case conversion |
pad(s, n), truncate(s, n) |
right-pad with spaces / keep the first n characters |
str(x) |
string form; compact JSON for non-strings |
type_text(x) |
the model's text form of a type (decimal(12, 2), domain email, varchar(320)); x may be an attribute or column object or its ty value |
default_text(x) |
the model's text form of a default (0, "pending", expr "now()"); x may be an attribute or column object or its default value |
All functions are also filters. Two filters have no function form: raw disables the automatic escaping
of the value, escape applies it explicitly.
Values printed
Strings print as they are, integers in decimal, booleans as true/false, null as nothing, arrays and
objects as compact JSON.
Automatic escaping
Every {{ }} output is escaped for the output format unless its filter chain contains raw:
- html:
& < > " 'become& < > " '; - csv: a value containing a comma, a double quote, a newline or a leading or trailing space is wrapped in double quotes, with inner quotes doubled;
- md:
|becomes\|and newlines become spaces; - txt: nothing.
The context
| variable | content |
|---|---|
model |
the model as JSON, exactly the shape of bluep export json (see docs/json-format.md): model.entities, model.relationships, model.subject_areas, model.domains, model.enums, model.glossary, model.targets, model.classifications, ... |
meta |
{"name", "version", "description"} of the model |
lint |
array of lint findings {"rule", "severity", "kind", "object", "message", "file", "line"} in report order |
vars |
the --var definitions as strings |
Example
owners.md:
# Entities owned by {{ vars.owner }}
{% for name, e in model.entities -%}
{% if default(e.properties.owner, "") == vars.owner %}
- `{{ name }}`: {{ default(e.description, "") }} ({{ len(e.attributes) }} attributes)
{%- endif -%}
{% endfor %}
bluep report devdata/models/saas --template-file owners.md --var owner=billing
Errors
Parse errors: unterminated '{{', unterminated '{%', 'endfor' without 'for', 'endif' without 'if',
'for' without 'endfor', expected identifier after 'for', unknown statement 'foo', unexpected token ')', unterminated string literal. Evaluation errors: unknown variable 'x', unknown function 'f',
unknown filter 'f', cannot iterate over string, cannot add string and integer, cannot compare array with integer, len() expects 1 argument(s), found 2. All are reported with the template name, line and
column of the offending marker or token.
Limitations
No macros, includes, inheritance, floating-point arithmetic, regular expressions or user-defined functions. Templates read the model; they cannot change it.
Related
- For deterministic XLSX and PDF output, see report formats.