Skip to content

19. Complete examples

Contents of ATD 0.1

(informative)

19.1 The examples

Beside this document, each a complete description that checks without findings:

File Shows
mindmap.atd, mindmap.notation.atd a diagram split over a root and a part, with script functions, constraints, operations, a capability and an xml binding
reading-list.atd a designer with a table surface and a yaml binding
notes.atd an editor with a text surface and a bullets binding
binding-json.atd, binding-lines.atd, binding-blocks.atd a binding of the json, lines and blocks families
binding-grammar.atd a binding of the grammar family, for Turtle, with its grammar inline (section 11.9)
binding-capability.atd a binding whose family is a capability

And the worked examples of section 2: fixtures/mindmap/basic/, mindmap.trace.json with mindmap.md, and capabilities/*/contract.json.

The tool descriptions under definitions/ are examples too, and atd-grammar.py --probe reads them with those beside this document: definitions/designers/hierarchical-requirement.atd, with its part hierarchical-requirement.markdown.atd, is a designer with a hierarchy surface, the widths of its columns, move with a place, binding types the type map maps as the document and as unreadable, and rule names with hyphens. The five editors under definitions/editors/ (plain-text.atd, markdown.atd, json.atd, xml.atd, yaml.atd) are editors with a text surface: files, token classes, checks and completion from sources the editor names, an outline of a model read by a capability, and a preview.

Three of them follow in full, the shortest of each kind that shows a binding. Each is a copy of the file beside this document. The guide for tool engineers explains how such a file is written, step by step, with the mind map, the Hierarchical Requirement Designer and the Markdown editor.

A diagram, binding-lines.atd:

atd 0.1

/// Variables and the links between them, one statement per line: the `lines` family, as the causal loop diagram's
/// `.cld` files are read (FBL's `causal-loop-diagram.fbl`, trimmed).
diagram example/influence version "0.1.0" {
  label "Influence diagram"

  model {
    element Variable {
      attribute name: string required
      attribute label: string
      labelAttribute: name
    }
    element Link {
      attribute from: Variable required
      attribute to: Variable required
    }
    relation Influence from Variable to Variable {
      derived: (diagram.nodes.filter(n, n.type == "Link").map(l, {'source': l.from, 'target': l.to}))
    }
  }

  notation {
    node Variable { shape ellipse  label @name }
    edge Influence { line { routing: bezier }  marker target arrow }
  }

  binding cld family lines {
    label "Influence diagram"
    claims files "*.cld"
    text { newline: crlf, finalNewline: true }
    comment: r"^\s*#"
    unmatched: report

    element Variable as variable line r"^\s*variable\s+(?<name>[^\s]+)(?:\s+(?<label>\x22[^\x22]*\x22))?\s*$" {
      attribute name from group "name" { empty: refuse }
      attribute label from group "label" { empty: remove }
      insert { place: after-last, emit: "variable {name}[ \"{label}\"]" }
      remove { cascade: [link] }
    }

    element Link as link line r"^\s*link\s+(?<from>[^\s]+)\s+->\s+(?<to>[^\s]+)\s*$" {
      attribute from from group "from" { references variable by name }
      attribute to from group "to" { references variable by name }
      insert { place: after-last, emit: "link {from} -> {to}" }
      remove {}
    }
  }
}

A designer, reading-list.atd:

atd 0.1

/// A reading list, one row per book, with text and number fields and one view: DESL's smallest example
/// (`minimal-table.des` and `minimal-table.fbl`) as a designer in ATD.
designer example/reading-list version "0.1.0" {
  label "Reading list"

  model {
    element Field {
      attribute name: string required
      attribute valueType: ValueType required
      labelAttribute: name
    }
    element View {
      attribute name: string required
      labelAttribute: name
    }
    element Book {
      contains Value ordered
      contains Value as values
    }
    element Value {
      attribute field: Field required
      attribute text: text
      attribute number: number
    }
    enum ValueType {
      text { label: "Text" }
      number { label: "Number" }
    }
  }

  persistence {
    ids: { strategy: "uuid-v4", encoding: base36, types: { Value: { strategy: derived, expression: (self.parent.id + "/" + self.field.id) } } }
  }

  constraint uniqueFieldNames for Field {
    rule document.elementsOfType("Field").filter(f, f.name == self.name).size() == 1
    severity error
    message "Two fields have this name."
    code: "reading-list.duplicate-field-name"
  }

  surface table {
    columns Field { name: name, valueType: valueType }
    rows Book
    cells Value { column: field }
    views View { name: name }
    valueType text "Text" {
      key: text
      editor: text
      comparisons: [is, contains]
      sort: text
      convert number parse
    }
    valueType number "Number" {
      key: number
      editor: number
      comparisons: [equals, greater-than, less-than]
      sort: number
      convert text written-form
    }
  }

  operation addBook "New book" for document {
    create Book
  }

  binding yaml family yaml {
    label "Reading list"
    claims { extensions: [".yaml", ".yml"], shared: true, marker: { rootKey: designer, value: "example/reading-list" }, origins: ["example/reading-list"] }
    text { newline: lf, indent: 2 }
    header { key: ded, value: "0.1", required: true }

    element Field as field at "/fields/*" {
      id from key "id"
      attribute name from key "name" { empty: refuse }
      attribute valueType from key "type" { empty: refuse }
      insert { place: after-last, container: "/fields", keys: [id, name, type] }
      remove { cascade: [value] }
    }
    element View as view at "/views/*" {
      id from key "id"
      attribute name from key "name" { empty: refuse }
      insert { place: after-last, container: "/views", keys: [id, name] }
      remove {}
    }
    element Book as book at "/books/*" {
      id from key "id"
      insert { place: after-last, container: "/books", create: { at: { under: "/" } }, keys: [id] }
      remove {}
    }
    element Value as value at "/books/*/values/*" {
      parent book slot values
      attribute field from key "field" {
        empty: refuse
        references field by id
      }
      attribute text from key "text" { empty: remove }
      attribute number from key "number" { empty: remove, number: shortest }
      insert { place: after-last, container: "values", create: { at: { after: id } }, keys: [field, text, number] }
      remove { container: remove-when-empty }
    }

    registration { createOnFirstPlacement: false }
    template """ded: "0.1"
designer: example/reading-list
fields:
  - id: {newid:field}
    name: Title
    type: text
views:
  - id: {newid:view}
    name: All books
"""
  }
}

An editor, notes.atd:

atd 0.1

/// Notes kept as a Markdown list: an editor whose text is the document, with an outline of the notes, folding by
/// note, a preview, and a `bullets` binding that reads the notes under the heading `Notes` as a tree.
editor example/notes version "0.1.0" {
  label "Notes"
  requires capability render.markdown@^1

  model {
    element Note {
      attribute title: string required
      attribute done: bool default false
      attribute detail: text
      contains Note ordered
      labelAttribute: title
    }
  }

  constraint titled for Note {
    rule self.title.trim() != ""
    severity warning
    message "A note needs a title."
    code: "notes.untitled"
  }

  surface text {
    files "*.notes.md"
    tokens markdown
    outline Note by title
    fold Note
    preview capability render.markdown { side: right }
    fix closeNote "Mark as done" {
      when !self.done
      set self.done = true
    }
  }

  binding notes family bullets {
    label "Notes"
    claims files "*.notes.md"
    header { line: r"^# ", required: false }
    section notes "Notes" { caseInsensitive: true }

    element Note as note line r"^\[(?<done>[ x])\] (?<title>.+)$" {
      within notes
      parent note
      attribute title from group "title" { empty: refuse }
      attribute done from group "done" { map: { "x": "true", " ": "false" } }
      attribute detail from continuation
      insert { place: after-last, emit: "- \\[{done}\\] {title}" }
      remove {}
    }
  }
}

19.2 The walk

walk/walk.json ($defs/Walk) is the walk of 30 edits and requests over the examples that every language server meets alike (SC-005): completion in a binding rule's attribute position, a rename across a description's files, typing on after a syntax error, formatting twice, and a description with a part.

19.3 The refused corpus

refused/ holds descriptions a checker refuses, each with the findings it must give (refused/README.md). atd check --corpus refused compares every one of them with its findings.

19.4 For agents

An agent writing a description is given grammar/atd.flat.lark, with which a model service constrains its output, two examples, and the findings of atd check --json, which it reads as data. Section 10 of the guide says how.

Referenced from