layout

package
v0.23.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 4, 2026 License: AGPL-3.0 Imports: 12 Imported by: 0

Documentation

Overview

Package layout generates BPMN diagram interchange (BPMN-DI) for models that carry none, and regenerates it for models whose layout a user has tangled. It is the server-side auto-layout the Modeler's "Auto-layout" button calls and the fallback that lets a semantic-only deployed model still render (ADR-0124), implemented as the layered pipeline — rank, order, place, route — whose invariants ADR-0127 pins down.

The package is deliberately free of any engine or server dependency: it reads BPMN XML with its own minimal structs and writes BPMN-DI back, nothing more. It runs when a human fetches or re-arranges a model, never on the processor's hot path.

Index

Constants

View Source
const (
	ChangeAdded   = "added"
	ChangeRemoved = "removed"
	ChangeChanged = "changed"
)

The kinds of change Changes reports, and of difference inside one.

Variables

View Source
var (
	// ErrNoDiagram means the incoming document carries no diagram interchange to
	// take — an empty <BPMNDiagram> included, since a plane with no shapes on it
	// would replace the stored picture with a blank canvas.
	ErrNoDiagram = errors.New("the model carries no diagram interchange")
	// ErrDifferentModel means the two documents do not describe the same process:
	// their semantic halves differ in some element, attribute or text. The diagram
	// is not transplanted, because a layout only means anything against the shapes
	// it was drawn for.
	ErrDifferentModel = errors.New("the model's semantic content differs from the stored one")
)

Errors Transplant returns. They are distinguished because the HTTP surface maps them to different statuses: a model whose meaning differs is the caller's mistake to fix (409), a body carrying no diagram is a malformed request (400).

Functions

func Difference added in v0.12.0

func Difference(a, b []byte, aName, bName string) (string, error)

Difference names the first place two BPMN documents part as models, or returns "" when they describe the same process. It is SameModel's question with the answer spelled out: the diagram is ignored, and so are formatting, attribute order and attributes written at their schema default.

aName and bName are how the sentence calls each side — "the deployed version", "the draft" — because the same walk answers two people: an operator whose layout save was refused, and a modeller asking whether the draft in front of them is the version that runs. Naming the documents is what lets the second one act on it.

An error means one of the documents is not well-formed XML.

func Ensure

func Ensure(src []byte) []byte

Ensure returns src unchanged if it already carries BPMN diagram interchange (a <BPMNDiagram>); otherwise it generates a simple left-to-right layered layout and injects one so bpmn-js can render the model. It is best-effort: on any parse or structural problem it returns src unchanged.

This runs when the UI fetches a model's XML — a rendering concern, never the engine hot path — so models deployed as pure semantic XML (no layout) still show up in the editor and the live overlay.

func EnsureReport added in v0.4.0

func EnsureReport(src []byte) ([]byte, bool)

EnsureReport is Ensure, additionally reporting whether it generated the layout — which a caller storing the result wants to know, so it can say where the diagram came from. False means the model already had one, or none could be generated; in both cases src comes back unchanged.

func Regenerate

func Regenerate(src []byte) []byte

Regenerate discards whatever diagram interchange the model already carries and generates a fresh left-to-right layout in its place. It backs the Modeler's "Auto-layout" button: a diagram a user has tangled by hand is re-flowed by the same generator that lays out a layout-less deployed model. Only shape and edge coordinates change — the semantic model (processes, flows, ids) is untouched.

Best-effort, like Ensure: if a new layout can't be generated (the XML won't parse, or the model has no layout-relevant nodes) src is returned unchanged rather than stripped of the layout it had.

func SameModel added in v0.5.0

func SameModel(a, b []byte) (bool, error)

SameModel reports whether two BPMN documents describe the same process — equal everywhere the engine looks, whatever their diagrams say. It is the question Transplant asks before it moves anything, exposed on its own so a caller can tell "you changed the model" from "the model won't parse" before offering to save a layout.

func Transplant added in v0.5.0

func Transplant(stored, incoming []byte) ([]byte, error)

Transplant returns the stored document with the incoming document's diagram interchange in place of its own. Only the picture moves: every byte of stored outside its <BPMNDiagram> blocks comes back unchanged, so the model the compiler already turned into a CompiledProcess is bit-for-bit the model it still holds — script bodies, documentation text, formatting and all.

It refuses with ErrDifferentModel unless the two documents' semantic halves are equal as XML (see semanticDigest), and with ErrNoDiagram if the incoming document has no shapes to give.

The incoming diagram is made self-contained on the way over: the namespace prefixes it uses are re-declared on the <BPMNDiagram> element itself, from the declarations its own document bound them to. Without that, a diagram written with prefixes the stored document's root does not declare would splice in as well-formed nonsense.

Types

type Change added in v0.23.0

type Change struct {
	// Kind is ChangeAdded (only in the newer document), ChangeRemoved (only in
	// the older) or ChangeChanged (in both, stating something different).
	Kind string `json:"kind"`
	// ID is the element's id. Empty for the document itself: what the root
	// <definitions> holds beside its elements, such as an import.
	ID string `json:"id"`
	// Type is the element's kind as the document spells it — "userTask",
	// "sequenceFlow" — in the newer document when it is in both.
	Type string `json:"type"`
	// Name is the element's name, the newer one when it is in both and has one.
	Name string `json:"name,omitempty"`
	// Parent is the id of the element it sits in — its process, sub-process or
	// lane set — in the newer document when it is in both.
	Parent string `json:"parent,omitempty"`
	// Details are what differs, for a changed element, in the order the newer
	// document states them. Empty for an added or a removed one.
	Details []Detail `json:"details,omitempty"`
}

Change is one element that differs between the two versions.

func Changes added in v0.23.0

func Changes(a, b []byte) ([]Change, error)

Changes lists every element in which two BPMN documents differ as models: added in b, removed from a, or stating something else. a is the older side and b the newer, so "added" means "in b and not in a". The changes come in b's document order, the removed ones after them in a's.

An error means one of the documents is not well-formed XML.

func Compare added in v0.23.0

func Compare(a, b []byte, aName, bName string) (string, []Change, error)

Compare answers both questions about two versions of a model at once: where they first part, as Difference names it ("" when they are the same model), and every element that differs, as Changes lists them. aName and bName name the two sides in the first difference. An error means one of the documents is not well-formed XML.

type Detail added in v0.23.0

type Detail struct {
	// Field names what differs, as a path inside the element: "name",
	// "conditionExpression", "extensionElements/zeebe:taskDefinition@type",
	// "extensionElements/zeebe:ioMapping/zeebe:input[total]@source". Two
	// fields belong to the element itself: "type", when the same id is now a
	// different kind of element, and "parent", when it moved to another container.
	Field string `json:"field"`
	// Kind is ChangeAdded when only the newer document states the field,
	// ChangeRemoved when only the older one does, ChangeChanged when both do.
	Kind string `json:"kind"`
	// Before and After are the field's values; the side that does not state it is
	// empty. A part with no text — <zeebe:userTask/> — has the empty value on the
	// side that has it, which Kind tells from absent.
	Before string `json:"before,omitempty"`
	After  string `json:"after,omitempty"`
}

Detail is one thing a changed element states differently.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL