JSONHTL — Notes-store extensions and compatibility

Parent: README. Base grammar: JSONHTL_SPEC. Machine validation: JSONHTL_SCHEMA.

Registered content extensions

list: {items: [...], ordered?: boolean, label?: string}. Canonical items are plain strings or arrays of inline elements. Compatibility forms include a single inline object, {para: inline-content}, and key/value record objects rendered as labelled fields. A bare array at block level is invalid.

{
  "list": {
    "ordered": true,
    "items": [
      "First step",
      [
        "Read ",
        {
          "link": {
            "href": "README",
            "text": "the guide"
          }
        }
      ]
    ]
  }
}

table: {columns: [string, ...], rows: [[cell, ...], ...], caption?: string}. Each row has exactly as many cells as columns. A cell is a plain string or an array of inline elements, using the same grammar as a paragraph. Structured links must render as links rather than stringified objects. Numeric values in older notes are display-tolerated but should be written as strings.

{
  "svg": {
    "body": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 50\"><rect width=\"100\" height=\"50\" fill=\"#eef\"/><text x=\"50\" y=\"30\" text-anchor=\"middle\">hello</text></svg>",
    "alt": "A light blue rectangle with the word hello",
    "caption": "Fig. 1 — minimal SVG block"
  }
}

svg: {body: string, alt?: string, caption?: string}. The body is a complete SVG document as a plain string (including the opening svg tag with xmlns). alt provides screen-reader text. caption appears below the image. Do NOT use the shorthand {svg: "..."} with a bare string — that form is not recognised by the renderer; the value must always be an object with a body field.

{
  "table": {
    "columns": [
      "Reference"
    ],
    "rows": [
      [
        [
          {
            "link": {
              "href": "README",
              "text": "Guide"
            }
          },
          {
            "bold": " recommended"
          }
        ]
      ]
    ],
    "caption": "Useful references"
  }
}

bold/strong: string-valued bold emphasis. em/italic: string-valued italic emphasis. All four are registered inline forms in paragraphs, list inline arrays and table cells.

Runnable documents

runnable: true enables codeblock.exec (boolean) and codeblock.name (string, unique across the entire document, including nested sections/details). Ordinary renderers display code and never execute it. Execution behaviour belongs to the Notes Browser; see README/runnable.

Canonical syntax and compatibility

Write codeblock.lang and codeblock.body. Older language/text aliases are retained only by compatibility renderers that already accepted them; the linter reports them and new producers must use canonical fields. Canonical fields take precedence when both are supplied. No corpus-wide automatic alias rewrite is performed.

Unknown blocks and inline elements are skipped by base consumers; schema validation reports them as unsupported. Malformed known elements are validation errors: validate before rendering rather than rely on renderer-specific recovery. Unknown top-level metadata is allowed by the base format.

bullet_list and writable_note remain application-specific, unregistered blocks. The web viewer's legacy support is not a promise of portable behaviour; use list for portable lists.

Consumer support

Web renderer (notes_web.py), both gdata desktop viewers, shared Envoy JSONHTLRenderer, and its static exporter support section, list, table, bold, image, svg and details. Nested section levels default to 2 at document root (below the document title) and parent effective level + 1, capped at 6; details is transparent to section depth.

Web/static details is browser-native and collapsible. wx.html desktop consumers expose its summary and content expanded; native collapse widgets remain separate UI work. The gdata desktop viewers rasterise SVG and decode raster images. The shared HTML renderer outputs image data URIs for browser display.

Linting

python3 lint_jsonhtl.py --key README
python3 lint_jsonhtl.py --file document.json --schema jsonhtl_schema.json
python3 lint_jsonhtl.py --all --metadata --links

The linter reads the live JSONHTL_SCHEMA by default; --schema accepts an offline copy. It checks nested blocks, aliases, runnable fields/names, table widths, and optionally notes-store metadata and internal hrefs. --links checks against the public key listing: references to private notes require manual classification, and unresolved hrefs are not proof that a note is orphaned.

Coordinated changes

Any future format change must update spec/registry, schema, linter, web renderer, desktop viewers, shared renderer/exporter, and compatibility tests together. Preserve existing notes; document producer rules and deliberate consumer fallbacks.

version 2  ·  created 2026-10-06  ·  updated 2026-10-06  ·  tags jsonhtl, reference, extensions