GAPS.md
61 lines · 4398 bytes
1# Conformance gaps
2
3OrgSwift is measured against the [org-conformance](../org-conformance) corpus, whose
4goldens come from orgo (validated against Emacs `ox-html`). The renderer is run in
5orgo-compatible mode — `OrgRenderOptions(metadataHeader: false, headingLevelOffset: 1)` —
6so that only real rendering differences remain.
7
8Of the 12 corpus cases, **11 match orgo exactly** — every case except `outofscope`, which is
9`scope: out` in the corpus (deliberately unsupported constructs like `#+INCLUDE`, babel, and
10LaTeX; orgo may also differ there, so it is documentation, not a target). The per-case state
11is recorded in the `expectations` map in `Tests/OrgSwiftTests/ConformanceTests.swift`: a case
12that regresses, or `outofscope` starting to match, fails the test and forces the map to be
13updated — that is how this list stays honest.
14
15Two behaviors were made configurable during extraction rather than left hardcoded, because
16they are presentation policy, not parser capability:
17
18- **`metadataHeader`** — whether `#+TITLE`/`#+AUTHOR`/`#+DATE` render as a leading
19 `<div class="org-metadata">`. Apps that want a visible README title keep the default
20 (`true`); orgo carries the title in the page template, so conformance runs with `false`.
21- **`headingLevelOffset`** — added to a heading's star count. Default `0` renders `*` as
22 `<h1>`; orgo uses `1` (`*` → `<h2>`, leaving `<h1>` for the title).
23
24## Closed
25
26- **`timestamps`** — active/inactive timestamps, times, same-day and multi-day ranges now
27 render as `<time class="timestamp" datetime>` elements matching orgo; day names and
28 repeater/warning cookies are dropped, non-timestamps (`3 < 4`, `[not a stamp]`) stay
29 literal.
30- **`footnote`** — references (`[fn:1]`), inline footnotes (`[fn:label:text]`), and
31 reference-style definitions now render as `<sup>` anchors plus a `<section
32 class="footnotes">` at the end, numbered in first-reference order. Footnote references
33 are collected from paragraphs and headings; a reference inside a list item or table cell
34 is not yet collected (it degrades to literal text).
35- **`minimal` / `headings`** — property drawers (`:PROPERTIES:` … `:END:`) are dropped
36 rather than rendered as a `<dl>`, and heading trailing `:tag1:tag2:` are split off the
37 title and rendered as `<span class="tag">`. TODO/DONE keywords and priority cookies are
38 still emitted as plain title text (orgo wraps them in styled spans); that is a separate,
39 cosmetic difference the skeleton does not distinguish.
40- **`core`** — bare `http(s)://` URLs in running text are autolinked (trailing sentence
41 punctuation left outside the link), and task checkboxes render as `<code>[ ]</code>` /
42 `<code>[X]</code>` / `<code>[-]</code>` the way org's HTML exporter emits them, rather
43 than as `<input type="checkbox">`.
44- **`images`** — `[[file:…]]` links have the `file:` prefix stripped and relative image
45 `src`/link `href` are allowed (a scheme-less path cannot carry a `javascript:` payload).
46 A standalone image line becomes `<p><img></p>`; an affiliated `#+CAPTION`/`#+ATTR_HTML`
47 promotes it to a `<figure>`, with a numbered `<figcaption>` when a caption is present.
48 `#+ATTR_HTML` `:key value` pairs (quoted values honored) become `<img>` attributes, and
49 a described image link (`[[file:x.png][text]]`) renders as a link, not an inline image.
50- **`elements`** — any unhandled `#+KEYWORD:` line (`#+FILETAGS`, `#+TBLFM`, …) is consumed
51 as document metadata instead of leaking into the body, and `[[id:target]]` links render
52 as in-page fragment links (`<a href="#target">`).
53- **`lists`** — the list renderer is now recursive: unordered/ordered nesting to any depth,
54 description lists (`term :: definition` → `<dl>`), and multi-paragraph items (an item's
55 paragraphs, separated by blank lines, wrap in `<p>`). A latent link-parser bug that let a
56 no-description link swallow a later link's `][` was fixed in passing.
57- **`tblfm`** — `^` superscript renders (`N^2` → `N<sup>2</sup>`, `x^{group}` supported).
58- **`blocks`** — example blocks are a bare `<pre>`; `#+BEGIN_EXPORT html` passes through
59 verbatim while other export backends are dropped; verse renders as `<p class="verse">`
60 with `<br>`; a `#+BEGIN_<name>` special block becomes `<div class="<name>">` with org
61 content; and a source block inside a quote stays nested in the `<blockquote>`.