rules_puml
Bazel-idiomatic PlantUML diagram rendering + composition (Java toolchain; SVG/PNG today, PDF + typed-AST planned)
| Latest | 0.0.2 |
|---|---|
| Versions | 2 |
| Category | Bazel rules |
| Maintainers | Matt Marshall |
| Registry | https://registry.tbzl.dev/modules/rules_puml/ |
| Source | github.com/tomato-bazel/rules_puml |
bazel_dep(name = "rules_puml", version = "0.0.2")
View source & releases on GitHub ↗
PlantUML diagram rendering + composition (Java toolchain, SVG/PNG/PDF output, LaTeX-embeddable)
Status: v0.0.1 — scaffold
No public surface yet. See CHANGELOG.md for what has shipped.
Install
.bazelrc:
common --registry=https://registry.fastverk.com/
common --registry=https://bcr.bazel.build/
MODULE.bazel:
bazel_dep(name = "rules_puml", version = "0.0.1") Usage#
Real usage, taken from the module’s examples/.
examples/pipeline/BUILD.bazel
load("@rules_puml//puml:defs.bzl", "puml_diagram", "puml_library")
# Single-source example: one architecture diagram, one .puml file.
puml_diagram(
name = "architecture_svg",
src = "architecture.puml",
output_format = "svg",
)
puml_diagram(
name = "architecture_png",
src = "architecture.puml",
output_format = "png",
)
# PDF rendering (0.0.2+) — vector PDF directly embeddable in LaTeX
# papers via `\includegraphics{architecture_pdf.pdf}`. No external
# toolchain needed; the renderer's classpath includes Apache Batik
# + FOP for the SVG→PDF step inside the same JVM invocation.
puml_diagram(
name = "architecture_pdf",
src = "architecture.puml",
output_format = "pdf",
)
# Composed example: same diagram, split into typed fragments to
# demonstrate the V1-shape composition. Preamble first, components
# next, interactions last — declaration order is compose order.
puml_library(
name = "preamble_lib",
srcs = ["fragments/preamble.puml"],
)
puml_library(
name = "actors_lib",
srcs = ["fragments/actors.puml"],
)
puml_library(
name = "components_lib",
srcs = ["fragments/components.puml"],
)
puml_library(
name = "interactions_lib",
srcs = ["fragments/interactions.puml"],
)
puml_library(
name = "closer_lib",
srcs = ["fragments/closer.puml"],
)
puml_diagram(
name = "architecture_composed",
libs = [
":preamble_lib",
":actors_lib",
":components_lib",
":interactions_lib",
":closer_lib",
],
output_format = "svg",
)Rules & providers#
Generated with Stardoc from the module's .bzl sources.
from docs/pdf-provider-proposal.md
PdfDocumentInfo — shared provider design proposal
Status: Draft. Coordinators: rules_puml (producer), rules_texlive (producer + canonical consumer), rules_firefox (future producer).
Why
Three Bazel modules in the fastverk ecosystem produce PDFs from different inputs:
| Module | Input | Output | Implementation |
|---|---|---|---|
rules_puml | .puml source | vector PDF (one diagram) | PlantUML + Batik + FOP, in-JVM |
rules_texlive (in flight) | LaTeX source tree | vector PDF (paper) | pdfTeX / tectonic |
rules_firefox (long horizon) | HTML / CSS | rasterized + vector PDF | headless Gecko |
The canonical consumer is a LaTeX paper that embeds many diagram
PDFs alongside its own content. Today the integration is ad-hoc:
the paper depends on diagram file labels by path. A shared provider
collapses that to a typed contract — the paper rule consumes any
target speaking PdfDocumentInfo, the producer doesn’t care which
paper consumes it.
This is the rules_rdf pattern: RdfDatasetInfo is the abstract
provider; rules_jena emits it from a Jena Model, rules_jsonschema
emits it from a SHACL shape; rules_rdf itself is the home of the
contract — no rules_jena ↔ rules_jsonschema dep at all. The
canonical RDF-consumer rules (sparql_query_test, etc.) live in
rules_rdf and accept any target with the provider.
Proposed shape
PdfDocumentInfo = provider(
doc = "A PDF document produced by any source — LaTeX, SVG render, " +
"HTML render. Consumed by document-assembly rules " +
"(tex_paper, presentation builds, archive bundles) that " +
"stitch many PDFs into one.",
fields = {
"pdf": "File: the rendered PDF document.",
"source_kind": "str: provenance only — 'tex' | 'svg' | 'html' | " +
"'png-to-pdf' | 'other'. Useful for diagnostics " +
"and per-source caching; never branched on by " +
"consumers.",
"page_count": "int | None: total pages when the producer can " +
"determine it cheaply (LaTeX knows; an SVG " +
"render is always 1; HTML to PDF only after the " +
"fact). None when not known.",
"logical_name": "str: stable handle used in includes, e.g. " +
"the label name. LaTeX consumers embed via " +
"\\includegraphics{<logical_name>} where the " +
"asset is symlinked into the paper's working " +
"tree at <logical_name>.pdf.",
},
)
Optional companion types (V1, not v0):
PdfTocInfo = provider(
doc = "Table-of-contents fragments contributed by a document " +
"(LaTeX produces these; SVG renders contribute none). " +
"Used by aggregator rules that build a combined TOC.",
fields = {
"entries": "depset[struct(title=str, page=int, level=int)]",
},
)
Toolchain types (V1)
When multiple SVG-to-PDF implementations matter (Batik in-JVM today; Inkscape if a consumer needs better gradient handling; rsvg-convert for batch speed), select via a toolchain:
svg_to_pdf_toolchain_type = "@rules_pdf//pdf:svg_to_pdf_toolchain_type"
html_to_pdf_toolchain_type = "@rules_pdf//pdf:html_to_pdf_toolchain_type"
Concrete impls:
rules_puml//puml/private/plantuml:plantumlalready satisfies an in-JVMsvg_to_pdf_toolchaincontract (Batik + FOP).rules_firefoxfuturefirefox_headlesswould satisfyhtml_to_pdf_toolchain.
V0 of this proposal does not require toolchain types — direct producer to consumer via the provider is enough. Toolchains land when a second SVG-to-PDF impl appears.
Where the provider lives
Three options ranked by cost:
A. Tiny new rules_pdf module (RECOMMENDED)
- Pure provider definitions, no rules, no Maven, no toolchains in V0. Ten lines of Starlark.
- Both
rules_pumlandrules_texlivedepend onrules_pdffor the contract type; neither depends on the other. - Mirrors
rules_rdfexactly — the abstract spec lives alone, the concrete impls live in named modules that emit the abstract type. - Cost: one new repo + registry entry. Maintenance is near-zero because the provider shape is small and stable.
B. rules_texlive owns the provider
- LaTeX-paper-build is the canonical consumer; semantically it’s the right home.
rules_pumlwouldbazel_dep(name = "rules_texlive")solely for the provider type. That’s a heavy dep — rules_texlive pulls in pdftex source, CWEB tooling, Lean, the works.- Pragmatic only if the rules_texlive author wants to own it AND a way exists to expose just the provider without pulling the full build graph.
C. rules_lang
- Considered, rejected. rules_lang scopes source-language ASTs and translators; PDF is an artifact format. Putting an artifact provider there stretches the term and creates the same “heavy dep for a small provider” problem as (B), only worse.
Recommendation: (A). Three-line registry entry, clean ownership, future-proof.
Coordination ask
For the rules_texlive author:
- Does (A) work for you — a tiny
rules_pdfyou depend on for the provider type alongside your existing build? - Are the fields right?
source_kind/page_count/logical_nameare best-guess minimum-viable; do you needbookmarks/creation_metadata/ anything else for the LaTeX include path? - Naming — is
PdfDocumentInfothe right name vs.PdfArtifactInfo,PdfInfoetc.?
Concrete next steps if (A) is approved
- Create
fastverk/rules_pdfrepo (~10 lines of Starlark). - Register
rules_pdf 0.0.1in the bazel-registry. rules_puml 0.0.3:puml_diagramemitsPdfDocumentInfowhenoutput_format = "pdf".rules_texlive:tex_paperemitsPdfDocumentInfo;tex_paperacceptsdiagrams = [...]where each is a label producingPdfDocumentInfo. LaTeX includes resolve bylogical_name.agora/papers/grounding: convert the TikZ pipeline figure to apuml_diagram(output_format = "pdf")and depend on it from the paper target. Demonstration of end-to-end integration.
Steps 3-5 are independent — rules_puml 0.0.3 ships as soon as rules_pdf 0.0.1 lands; agora’s paper consumes when both are in.
Conformance#
No gate findings. 8 contested atoms. See how gating works or the full report.
Contested atoms
Third-party modules where this module resolves a different version than others do. Not a violation of anything this module did — it is the actionable form of a registry-level convergence finding, and the sentence a maintainer can act on.
| Atom | Resolved here | Elsewhere |
|---|---|---|
apple_support | 1.24.2 | 2.2.0 ×1 |
bazel_skylib | 1.8.2 | 1.9.0 ×2 |
nlohmann_json | 3.6.1 | 3.12.0.bcr.1 ×1 |
protobuf | 33.4 | 34.0.bcr.1 ×2 |
rules_jvm_external | 6.7 | 6.8 ×4 |
rules_python | 1.7.0 | 2.0.1 ×1 |
rules_swift | 3.1.2 | 3.6.1 ×1 |
upb | 0.0.0-20220923-a547704 | 0.0.0-20230516-61a97ef ×1 |
Dependencies#
Depends on
Versions#
2 published versions, newest first. Each resolves to an immutable, integrity-checked archive.
| Version | Integrity (sha256) | Source archive |
|---|---|---|
0.0.2 latest | Q+Y9x7LRguxGqPZ6… | tag archive ↗ |
0.0.1 | 9a5/N61sAEiiaQBY… | tag archive ↗ |
Changelog#
All notable changes to rules_puml. The format is loosely Keep a Changelog — version headers mirror the published bazel-registry entries.
0.0.2 — PDF rendering via PlantUML + Batik/FOP
puml_diagram(output_format = "pdf")now ships. PlantUML’s-tpdfmode delegates to Apache Batik’sSVGConverterand Apache FOP for the SVG→PDF step; both Maven artifacts are added to the rendererjava_binary’s classpath, so PDF mode requires no external toolchain (no Inkscape, no rsvg-convert, no headless browser). Output is vector PDF, LaTeX-embeddable via\includegraphics{foo.pdf}directly.- Maven additions:
org.apache.xmlgraphics:batik-rasterizer:1.18,org.apache.xmlgraphics:fop:2.10. Both bring their transitive Batik / xmlgraphics-commons / avalon-framework modules with them. - This satisfies the “LaTeX papers embed diagram PDFs” path the
paper integration roadmap was waiting on. A follow-up will emit
a shared
PdfDocumentInfoprovider once its home (rules_texlive vs. a new tiny rules_pdf module) is settled with the other agents.
0.0.1 — V0 macros (file-level render + library composition)
- Initial release.
puml_diagram(name, src | libs, output_format)puml_library(name, srcs)macros, SVG/PNG output, providers (PumlSourceInfo,PumlDiagramInfo), Java-binary renderer wrapping PlantUML 1.2024.7.