tomato·bazeldocs v0 · latest
Docs/Reference/Modules/rules_puml

rules_puml

Bazel-idiomatic PlantUML diagram rendering + composition (Java toolchain; SVG/PNG today, PDF + typed-AST planned)

Latest0.0.2
Versions2
CategoryBazel rules
MaintainersMatt Marshall
Registryhttps://registry.tbzl.dev/modules/rules_puml/
Sourcegithub.com/tomato-bazel/rules_puml
MODULE.bazelstarlark
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:

ModuleInputOutputImplementation
rules_puml.puml sourcevector PDF (one diagram)PlantUML + Batik + FOP, in-JVM
rules_texlive (in flight)LaTeX source treevector PDF (paper)pdfTeX / tectonic
rules_firefox (long horizon)HTML / CSSrasterized + vector PDFheadless 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_jenarules_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:plantuml already satisfies an in-JVM svg_to_pdf_toolchain contract (Batik + FOP).
  • rules_firefox future firefox_headless would satisfy html_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:

  • Pure provider definitions, no rules, no Maven, no toolchains in V0. Ten lines of Starlark.
  • Both rules_puml and rules_texlive depend on rules_pdf for the contract type; neither depends on the other.
  • Mirrors rules_rdf exactly — 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_puml would bazel_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:

  1. Does (A) work for you — a tiny rules_pdf you depend on for the provider type alongside your existing build?
  2. Are the fields right? source_kind / page_count / logical_name are best-guess minimum-viable; do you need bookmarks / creation_metadata / anything else for the LaTeX include path?
  3. Naming — is PdfDocumentInfo the right name vs. PdfArtifactInfo, PdfInfo etc.?

Concrete next steps if (A) is approved

  1. Create fastverk/rules_pdf repo (~10 lines of Starlark).
  2. Register rules_pdf 0.0.1 in the bazel-registry.
  3. rules_puml 0.0.3: puml_diagram emits PdfDocumentInfo when output_format = "pdf".
  4. rules_texlive: tex_paper emits PdfDocumentInfo; tex_paper accepts diagrams = [...] where each is a label producing PdfDocumentInfo. LaTeX includes resolve by logical_name.
  5. agora/papers/grounding: convert the TikZ pipeline figure to a puml_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.

AtomResolved hereElsewhere
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#

rules_puml in the registry graph — what it depends on (left) and what depends on it (right).

Depends on

platforms1.0.0bazel_skylib1.8.2rules_java8.6.1rules_jvm_external6.6rules_shell0.6.1devstardoc0.7.2dev

Versions#

2 published versions, newest first. Each resolves to an immutable, integrity-checked archive.

VersionIntegrity (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 -tpdf mode delegates to Apache Batik’s SVGConverter and Apache FOP for the SVG→PDF step; both Maven artifacts are added to the renderer java_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 PdfDocumentInfo provider 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.

← All modules