Skip to content

11. Persistence plugins

Contents of FBL 0.12

11.1 Where a plugin sits

Some formats are too intricate to declare: projecting Turtle triples onto cards and rows, evaluating MSBuild with its imports and wildcards, parsing SPARQL. For them a binding's reader is a persistence plugin:

{ "reader": { "plugin": "net.etalii.adp.w3c.turtle", "version": "^0.1.0" } }

The plugin is declared in the DISL specification's plugins with provides: ["persistenceFormat"] (DISL §13.1); args are validated against its declaration. Everything else in the binding is declared and done by the host exactly as for a declared reader: claims and routing, the registration, several readings, folder recognition and watching, templates, history, drift and saving. A format FBL can declare SHOULD be bound rather than read by a plugin; (FBL 0.9) a format with a context-free syntax can be declared with the grammar family (section 4.9).

11.2 Operations

A plugin implements these operations, stated as data exchanged so that each host binds them to its own plugin mechanism:

Operation Receives Delivers
read The body's bytes (a file body), or for a folder subject the relative path and bytes of every file the file rules select; the binding's args. The elements and relations: type, id, parent and slot, attribute values; for each, the source span of the entry and of every writable value (file, byte range); the findings, with source locations; and whether the body is unreadable as a whole.
plan The current bytes, the last read result, and one model change (below): add, set, remove, move or retype an element or relation. The splices that realise it, each {operation, file, start, end, text} with an operation from section 6.1; or a refusal with the sentence the host shows.
template The new body's name and the template placeholders (section 13). The bytes of a new body. Only asked when the binding has no template.text.
watch The last read result (folder subjects, optional). The paths the reading depends on beyond the file rules; the host watches them too.

Model changes (FBL 0.2). The change plan receives is one of these, each an object with the change's name as its one key ($defs/ModelChange):

Change Fields
add type, id (optional), attributes, parent (optional), slot (optional), position (optional)
set id, attributes
remove id
move id, parent (null for the top level), slot (optional), position
retype id, type, attributes (the values after the type's attributeMapping, DISL §9.5)

where position ($defs/ChangePosition) is { "index": int }, { "after": id } or { "before": id }. A plugin declares which changes it plans in its DISL declaration (DISL §13.1): "plans": ["add", "set", "remove", "move", "retype"], with "add": { "position": true } when it honours a position, and "move": { "position": true } likewise. Without plans, a plugin plans add, set and remove.

  • A host MUST send an add with position when the change came from an ordered placement (DISL create with after or before, a parent placement, a drop), and a plugin that declares add.position MUST insert at that position or refuse.
  • A host MUST send a reorder or a re-parent as one move, never as a remove and an add, so the plugin can splice the element's bytes unchanged; a plugin that does not declare move gets the remove and the add instead.
  • A host MUST send a DISL retype as one retype; a plugin that does not declare retype MUST be sent a remove and an add, and the host MUST warn that identity and unbound bytes may not survive.
  • An index MUST be counted among the parent's children in the slot after the element was removed from its old place, so the same index means the same thing for a move within one parent and across parents.
{ "move":   { "id": "1.2", "parent": "1", "position": { "index": 2 } } }
{ "retype": { "id": "1.3", "type": "Check", "attributes": {} } }
{ "add":    { "type": "Check", "attributes": { "label": "New question" }, "parent": "1", "position": { "index": 1 } } }

An agent behavior model's Markdown plugin declares all five changes and positions. Move later on 1.2, the second of three children of 1, sends the move above; changing 1.3 from Do to Check sends the retype; a drop under 1 between its first and second child sends the add. Each becomes line splices that keep every other byte.

11.3 What the host does

The host, not the plugin, applies splices to bytes and saves them atomically; keeps the history and undoes with inverse splices or snapshots; checks drift; watches the body and calls read again after external changes; stores view data in the registration; routes files; and shares one open body between readings. A plugin-backed body therefore behaves exactly as a declared one: byte-preserving writes, exact undo, drift refusal, several readings, folder subjects.

11.4 What the plugin must do

  • read MUST NOT fail on content: problems are findings, and an unreadable body is reported as such (section 7).
  • read and plan MUST be deterministic: the same bytes and change give the same result, in every host's implementation of the plugin.
  • Splices from plan MUST change only the bytes the change concerns, MUST name their operation truthfully, and MUST follow the new-text rules of section 6.3 where they apply to the format.
  • A plugin MUST NOT write files, keep its own undo history, or store view data. A read-only binding's plugin is never asked to plan.
  • A plugin MAY report findings about anything in the body, with DISL's source location and subject; the host shows them like any other finding.

11.5 The formats expected to stay plugins (informative)

Format Tool types Why a plugin
Turtle and N-Triples W3C RDF, OWL, SHACL, SKOS Terms span tokens, prefixes compress IRIs, and one IRI yields several elements; the projection is code. (FBL 0.9) Turtle's syntax is read by the grammar family in w3c-turtle-grammar.fbl, and spec 035 binds the W3C RDF type's Turtle with it.
SPARQL 1.1 SPARQL query A recursive grammar projected onto scopes; read-only.
.sln, .slnx, MSBuild projects .NET dependency graph Wildcards, imports and central package management are evaluated; read-only.
Ansible project folders Ansible structure YAML and INI inventories, task directives and role resolution; read-only.
Helm chart folders Helm chart Templates are scanned as lines, not YAML, and includes resolved; read-only.
Azure Pipelines template expansion Azure DevOps pipeline Following template: references and unwrapping ${{ }} expressions is evaluation; the rest of the file could be declared.

Referenced from