Skip to content

2. Foundations

Contents of DISL 0.1

2.1 Serialization

A DISL specification is a JSON text (RFC 8259) encoded in UTF-8 without a byte-order mark. Its top-level value MUST be an object. The file extension SHOULD be .dis.

A specification SHOULD declare the schema it conforms to, and MUST declare the DISL version it targets:

{
  "$schema": "https://etalii.net/adp/disl/schema/0.1/disl.schema.json#/$defs/Specification",
  "disl": "0.1",
  "language": { "id": "org.example.statemachine", "version": "1.0.0" },
  "metamodel": { "types": {} }
}

The schema is published by the ADP website at https://etalii.net/adp/disl/schema/<version>/disl.schema.json.

Tools MAY accept YAML or JSON5 input for authoring convenience and convert it to JSON before processing, but the normative form is JSON. Because JSON has no comments, explanations belong in doc objects (section 2.4), which has the side effect that they reach end users.

Duplicate keys within one JSON object are a specification error. Property order in specifications carries no meaning except where this specification says so explicitly (arrays are always ordered; the order of toolbox groups, form fields, labels and constraints is significant).

2.2 Identifiers

Identifiers name types, attributes, styles, shapes, tools, constraints and all other named objects.

  • A simple identifier matches ^[A-Za-z_][A-Za-z0-9_]*$. Type names, attribute names, parameter names, port names and function names MUST be simple identifiers so that they are valid CEL identifiers.
  • A qualified identifier matches ^[A-Za-z_][A-Za-z0-9_-]*(\.[A-Za-z_][A-Za-z0-9_-]*)*$ and is used for language IDs, theme tokens (color.surface), names from imports (std.cylinder) and plugin names.
  • Identifiers are case-sensitive. Two identifiers in the same namespace MUST NOT differ only in case, to keep specifications and DID definitions portable across case-insensitive systems.
  • Where an object is stored in a map, the map key is its identifier. Where it is stored in an array, it carries an id property.

Namespaces. Each of the following is a separate namespace: types (node types and relation types share one namespace), enums and data types (share one namespace, which must also not clash with types), axes, coordinate systems, snapping profiles, styles, shapes, markers, icons, forms, tools, templates, constraints, operations, functions, layouts and viewpoints. Imported specifications contribute names prefixed with their alias (alias.Name).

Reserved names. The following MUST NOT be used as attribute names, because they are built-in fields of elements in CEL (section 12.2): id, type, kind, parent, children, descendants, ancestors, incoming, outgoing, source, target, sourcePort, targetPort, ports, owner, view, diagram, self, value, item, index, env, old, event, and any name beginning with _ or $. CEL keywords (in, as, break, const, continue, else, for, function, if, import, let, loop, package, namespace, return, var, void, while, true, false, null) are also excluded.

2.3 Localized text

Any human-facing string (labels, messages, descriptions, placeholders) is a LocalizedText: either a plain string or an object mapping BCP 47 language tags to strings.

{
  "label": "State",
  "label": { "en": "State", "de": "Zustand", "nl": "Toestand" }
}

When a map is given, it SHOULD include the locale declared in language.defaultLocale (default "en"). Runtimes select the best match for the user's locale (RFC 4647 lookup) and fall back to the default locale, then to the first entry in the map.

Where a human-facing string must contain computed values (constraint messages, dynamic tooltips), the object form { "cel": "..." } returning a string (or a map(string, string) keyed by locale) is used instead. DISL deliberately has no second template syntax.

2.4 Documentation objects

Every object in a specification MAY carry a doc property — the language itself, types, attributes, enum values, data types, axes, coordinate systems, snapping rules, styles, shapes, shape parameters, handles, markers, node and edge notations, labels, compartments, forms, fields, tool groups, tools, templates, constraints, hooks, operations, layouts, persistence settings and migrations. This is the mechanism that keeps users informed: a runtime can explain any element, field, tool, rule or snapping behavior it presents.

doc is either a LocalizedText (shorthand for summary) or a Doc object:

Property Type Meaning
summary LocalizedText One sentence of plain text. Used for tooltips, palette entries and hover cards.
description LocalizedText Longer explanation in CommonMark. Used in help panels, inspector help and generated reference docs.
rationale LocalizedText Why this rule or design exists. Particularly useful on constraints and snapping rules.
examples array of {title, description, value} Illustrations; value is arbitrary JSON (for example a sample attribute value).
seeAlso array of {title, href} Links. External links are absolute URIs; internal links are JSON Pointer fragments into the specification (#/metamodel/relations/Transition).
tags array of strings Keywords; used by toolbox search and documentation indexes.
audience array of "user", "author", "developer" Intended readers; "author" means the tool engineer. Absent means all. Runtimes SHOULD show only user documentation to end users when an audience is declared.
since string Language version (SemVer) in which the object appeared.
deprecated boolean or {since, message, replacedBy} Marks the object deprecated. Runtimes SHOULD warn when a deprecated type, attribute or tool is used and MAY offer replacedBy as a quick fix.
image string (URI) An illustration, for example a rendered sample.
helpUrl string (URI) A page with extended help; runtimes SHOULD render a "Learn more" link.
{
  "doc": {
    "summary": "A condition the system can be in.",
    "description": "A **state** is a stable situation in which the system waits for a trigger.\n\nStates may declare an *entry action* that runs each time the state is entered.",
    "tags": ["behavior", "core"],
    "seeAlso": [{ "title": "Transitions", "href": "#/metamodel/relations/Transition" }]
  }
}

Documentation surfaces. A conforming runtime at level Standard or above (section 15) SHOULD:

  • show a tool's doc.summary as its tooltip, and match label, doc.summary and doc.tags in toolbox search;
  • show an attribute's or field's doc.summary beneath or beside the form field, and doc.description on demand;
  • show a constraint's label, doc.summary and doc.rationale alongside every problem it reports, and list its quick fixes;
  • show the doc of axes, coordinate systems and snapping rules in canvas settings, ruler tooltips or a status bar while dragging (for example "Snapping to working days: tasks start at the beginning of a working day");
  • show a node or edge type's doc in a hover card on the canvas when a help mode is active;
  • offer a help view that renders the whole specification's documentation, including rendered samples of shapes and markers.

A label is distinct from doc: it is the short display name of an object (for example "Initial state" for the type InitialState). If label is absent, runtimes derive one from the identifier by splitting camel case and snake case and capitalising the first word only (InitialState → "Initial state", due_date → "Due date").

2.5 Expressions and dynamic values

All dynamic values are written in CEL. DISL uses four embeddings, and this document states for every property which one applies.

(a) Expression. A property of type Expression always contains CEL. It is written either as a bare string or as an object that adds documentation and an expected result type:

{
  "rule": "self.name != ''",
  "rule": { "cel": "self.name != ''", "resultType": "bool", "doc": "Every state needs a name." }
}

If resultType is present, validators MUST check that the static type of the expression is assignable to it.

(b) Bindable value. A property of type Bindable<T> accepts a literal of type T or one of these objects:

Form Meaning
{ "cel": "…" } Computed from a CEL expression.
{ "attribute": "path" } The value of an attribute of the current element (dotted path into structs, for example "address.city"). When the property is user-editable (a label, a placement coordinate), the binding is two-way: edits write back to the attribute.
{ "token": "name" } A theme token (section 6.2), resolved for the current theme mode.
{ "param": "name" } A parameter of the enclosing shape, marker or template.

Because literals may be strings, a bare string in a Bindable position is always a literal; a CEL expression there MUST use the {"cel": …} form.

(c) Geometry expression. In shape paths, handle positions and part bounds (section 6.8), a coordinate is a GeomExpr: a number (canvas units), a percentage string ("50%" of the relevant dimension), or any other string, which is CEL returning double or int. Geometry is so dense with expressions that the shorter form pays for itself.

(d) Action expression. In behavior actions, template fragments and migration steps (sections 7.4, 9 and 11.9), every value position is an Expression, so strings are always CEL. A string literal is therefore written with CEL quotes: "'Untitled'". The exceptions are keywords and names that the schema restricts to fixed values or identifiers — as, call, plugin, severity, algorithm, form, label (label id) — which are never CEL.

Evaluation guarantees. Expressions are free of side effects by construction. Runtimes MUST impose a cost limit using CEL's cost estimation, and SHOULD reject at validation time any expression whose worst-case estimated cost exceeds the limit declared in language.limits.celCost (default 1 000 000). At run time, an expression that fails (for example division by zero, missing key, cost exceeded) is handled according to its context:

Context On evaluation error
Constraint rule Reported as a problem with the constraint's severity and the message "could not be evaluated: …"; never silently passes.
Visual property, label, visibility The property falls back to its default; a diagnostic is logged; rendering continues.
Placement binding The element is drawn at its last valid position and marked as invalid.
Snapping function The unsnapped value is used.
Behavior action, hook, operation The whole transaction is rolled back and the error reported to the user.
Migration Loading the DID definition fails with a descriptive error; the original file is left untouched.

Static checking. Every expression is evaluated in a well-defined context that determines which variables exist and what types they have (section 12.3). Validators MUST type-check every expression in its context, using attribute types from the metamodel. Expressions whose type cannot be determined statically (for example because they use dyn) are permitted but SHOULD produce a validator warning.

2.6 Values and units

Kind Representation
Canvas length A number in canvas units (the unit of the coordinate system's numeric axis, px by default), or a string with an explicit unit: "12px", "4mm", "0.5in", "1.5em", "50%". Percentages refer to the containing box's corresponding dimension. em refers to the current font size.
Screen length Quantities that must stay constant on screen regardless of zoom — hit areas, snap tolerances, handle sizes, minimum marker sizes — are always in screen pixels and the property name ends in ScreenPx.
Color A CSS Color Level 4 string: "#1D9E75", "#1D9E75CC", "rgb(29 158 117 / 80%)", "hsl(160 69% 37%)", "oklch(0.62 0.12 165)", named colors, "transparent", "currentColor" (the resolved text color of the element).
Angle A number of degrees, clockwise, 0 pointing in the positive x direction.
Fraction A number from 0 to 1 inclusive.
Size [width, height].
Insets A number (all sides), [vertical, horizontal] or [top, right, bottom, left].
Point [x, y] for numeric axes, or {"x": …, "y": …} when axis values are timestamps or categories.
Timestamp An RFC 3339 string ("2026-10-01T09:00:00Z"), a full-date string ("2026-10-01") or an epoch number, as declared by the axis (section 5.4).
Duration An ISO 8601 duration ("P3D", "PT15M", "P1W") or a CEL duration string ("15m", "36h"). Calendar durations (P1M, P1Y) are only allowed where the property explicitly accepts calendar units, such as time snapping.

2.7 References

  • Type references are identifiers from the type namespace, optionally prefixed with an import alias (bpmn.Task). Wherever a single type is expected, a list of types MAY be given where the schema allows it; a type reference always includes all subtypes.
  • Library references — to styles, shapes, markers, icons, forms, tools, snapping profiles — are identifiers of entries in the respective library, or an inline object of the same kind.
  • JSON Pointer references ("#/notation/styles/base") are used in doc.seeAlso and in error reports.
  • A reference to an undefined name is a specification error. A reference to a deprecated object is a validator warning.

2.8 Extension properties

Any object in a specification or DID definition MAY contain properties whose names begin with x- (for example x-acme-simulation). Their content is unconstrained. Conforming tools MUST ignore extension properties they do not understand and MUST preserve them unchanged when rewriting a file. Section 13 describes plugins, the structured way to add behavior.

2.9 Versioning

  • disl (required) is the version of DISL the specification targets, as "major.minor". A runtime MUST refuse a specification with a higher major version than it supports and SHOULD warn for a higher minor version. The deprecated alias of section 18 is still read.
  • language.version (required) is the semantic version (SemVer 2.0.0) of the defined language. DID definitions record the language version they were written with; this drives migrations (section 11.9).
  • A change that can make previously valid DID definitions invalid or change their meaning is a major change; adding optional constructs is a minor change; documentation, visual and toolbox-only changes are patch changes. Validators MAY warn when a version increment does not match the observed difference to a previous specification.

Referenced from