')}\n`, 'a carry element shows what adfToHtml writes for its node, as it or a browser spells it, then ; to change the node, edit its ADF and write the HTML again: found "collation.a\n', 'a of the dialect is a carry element, holding class="adf-carry" and then data-adf alone, or opens with class="adf-emoji" or "adf-status": found "a\\n"'],
+ ['
a
\n', 'a of the dialect is a carry element, holding class="adf-carry" and then data-adf alone, or opens with class="adf-emoji", "adf-mention" or "adf-status": found "a\\n"'],
['\n', 'a carry element spells its node\'s JSON canonically: compact, keys sorted, each character HTML cannot hold spelled as a JSON escape: found "{ "type":""…'],
[`${documentCarry}\n\n`, 'a carry element holding the document stands alone, as the whole document: found "\\n\\n"'],
[`\n${documentCarry}\n`, 'a carry element holding the document stands alone, as the whole document: found "
\n
a
\n\n', ' takes start once, before its data-* attributes: found start after start'],
['
x
\n', 'data-wrap holds no boolean written as compact JSON'],
['
\n', ' holds its text, which is not empty: found "\\n"'],
- ['
\n', ' shows the day its data-timestamp names, in datetime and as its text; to change the date, change all three: found "x\\n"'],
['
a
\n', ' takes no data-size attribute'],
['
a&b
\n', 'text escapes & as &, < as < and > as >, and holds no character HTML cannot hold: found "&b\\n"'],
diff --git a/src/html/parse/node-element.ts b/src/html/parse/node-element.ts
index 72bc8b0..8cafaa6 100644
--- a/src/html/parse/node-element.ts
+++ b/src/html/parse/node-element.ts
@@ -1,41 +1,29 @@
-import type { AdfAttributes, AdfNode } from '../../adf/document.ts'
+import type { AdfNode } from '../../adf/document.ts'
import { foundAt, misspelledText, refused, type Place, type ReadNode, type StartTag } from './source.ts'
-import { htmlDay, nodeTypeOfElement, type NodeElement } from '../node-element.ts'
+import { nodeTypeOfElement } from '../node-element.ts'
import { readDataAttributes } from '../data-attributes.ts'
-import { shownText } from '../../adf/shown-text.ts'
import { success } from '../../result.ts'
import { misspelledAt, unescapedValue } from '../escaping.ts'
-// `undefined` where the tag opens no emoji, status, date or card element; one that does reads as the node `nodeElement` wrote it from, or is refused.
+// `undefined` where the tag opens no emoji, mention, status, date or card element; one that does reads as the node `nodeElement` wrote it from, or is refused.
export function readNodeElement(html: string, tag: StartTag, place: Place): ReadNode | undefined {
const [kind, ...rest] = tag.attributes
const found = kind?.[0] === 'class' ? nodeTypeOfElement(tag.name, kind[1]) : undefined
if (found === undefined) return undefined
const [type, model] = found
- if (model.leading !== undefined && rest[0]?.[0] !== model.leading) return refused('unmappable-html', `<${tag.name} class="${model.class}"> holds ${model.leading} first, before its data-* attributes: ${foundAt(html, tag.start)}`, html, tag.start, place)
- const data = readDataAttributes(rest, `${tag.name} class="${model.class}"`, model.vocabulary, model.textAttribute === undefined ? [] : [model.textAttribute], model.leading)
+ const name = `<${tag.name} class="${model.class}">`
+ if (model.leading !== undefined && rest[0]?.[0] !== model.leading.name) return refused('unmappable-html', `${name} holds ${model.leading.name} first, before its data-* attributes: ${foundAt(html, tag.start)}`, html, tag.start, place)
+ const data = readDataAttributes(rest, `${tag.name} class="${model.class}"`, model.vocabulary, model.written, model.leading?.name)
if (data.fault !== undefined) return refused(data.fault.code, data.fault.message, html, tag.start, place)
const closer = `${tag.name}>`
const stop = html.indexOf('<', tag.end)
const end = stop < 0 ? html.length : stop
const shown = unescapedValue(html.slice(tag.end, end), 'text')
if (shown === undefined) return misspelledText(html, tag.end + misspelledAt(html.slice(tag.end, end), 'text'), place)
- if (!html.startsWith(closer, end)) return refused('unmappable-html', `<${tag.name} class="${model.class}"> holds its text, then ${closer}: ${foundAt(html, end)}`, html, end, place)
- const node = nodeOf(type, model, data.value, shown)
- const expected = model.textAttribute === undefined ? htmlDay(shownText(node)) : shown
- if (expected === undefined || expected === '' || shown !== expected || (model.leading !== undefined && rest[0]?.[1] !== expected)) {
- return refused('unmappable-html', `${mismatch(tag.name, model)}: ${foundAt(html, tag.end)}`, html, tag.end, place)
+ if (!html.startsWith(closer, end)) return refused('unmappable-html', `${name} holds its text, then ${closer}: ${foundAt(html, end)}`, html, end, place)
+ const node: AdfNode = { attrs: model.build(data.value, shown), type }
+ if (model.shown(node) !== shown || (model.leading !== undefined && model.leading.value(node) !== rest[0]?.[1])) {
+ return refused('unmappable-html', `${name} ${model.mismatch}: ${foundAt(html, tag.end)}`, html, tag.end, place)
}
return success({ end: end + closer.length, node })
}
-
-function nodeOf(type: string, model: NodeElement, data: AdfAttributes, shown: string): AdfNode {
- return { attrs: model.textAttribute === undefined ? data : { ...data, [model.textAttribute]: shown }, type }
-}
-
-function mismatch(name: string, model: NodeElement): string {
- const element = `<${name} class="${model.class}">`
- if (model.leading === 'datetime') return `${element} shows the day its data-timestamp names, in datetime and as its text; to change the date, change all three`
- if (model.leading === 'href') return `${element} holds one URL, as its href and as its text; to change the card, change both`
- return `${element} holds its text, which is not empty`
-}
diff --git a/todo.md b/todo.md
index df6787b..47a08fe 100644
--- a/todo.md
+++ b/todo.md
@@ -12,7 +12,7 @@
| ID | Release | Blocked by | Exempt | Item | L | E | I | R | S | Moves | Score |
|---|---|---|---|---|---|---|---|---|---|---|---|
-| 133 | 0.3.0 | | question | **Write mentions, and inline cards holding `data` or a link mark, as semantic HTML in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 4 | 6 by 3 | 3.0 |
+| 133 | 0.3.0 | | question | **Write an inline card a link marks as semantic HTML in `adfToHtml` and read it back in `htmlToAdf`, in place of the carry element.** | 2 | 2 | 2 | 4 | 4 | 6 by 3 | 3.0 |
| 163 | 0.3.0 | | | **Gather a corpus of real-world ADF documents from public Jira and Confluence sites, each recording where it came from and under what licence.** | 3 | 2 | 4 | 7 | 4 | 6 by 3 | 3.0 |
| 164 | 0.3.0 | 163 | | **Publish a feature table setting chosen corpus examples beside what each call writes for them, readable at a glance by people and parseable by LLMs, and kept current by the gate.** | 3 | 2 | 1 | 4 | 5 | 3 by 6, 6 by 4 | 6.2 |
| 165 | 0.3.0 | 164 | | **Have a reader panel seated from `## Audience` judge each feature-table row reasonable or not, and file an item for each row it rejects.** | 2 | 2 | 1 | 3 | 3 | 6 by 5 | 7.5 |
@@ -69,23 +69,18 @@
## Details
-### 133. Write mentions, and inline cards holding `data` or a link mark, as semantic HTML in `adfToHtml` and read them back in `htmlToAdf`, in place of the carry element.
+### 133. Write an inline card a link marks as semantic HTML in `adfToHtml` and read it back in `htmlToAdf`, in place of the carry element.
-The fifth writer panel (`docs/decisions.md` §The HTML dialect) did not reach 5 of 7 on two
-spellings, so mentions and cards holding `data` ride the carry until the maintainer settles them.
-Class: the HTML dialect's spellings. Earlier entries: `data-*` named as HTML's `dataset` names it,
-`data-local-id` over `data-adf-local-id`. Candidates, each following those entries:
+Mentions and cards holding `data` are elements since the maintainer took the fifth writer panel's
+leading spellings (`docs/decisions.md` §The HTML dialect). A card a link marks still rides the carry,
+which shows the link's target as the link and the card's URL as its text, so both stay in sight.
+Atlassian's schema gives no card a link mark, so only a hand-built document meets this.
-- a mention as `@Mikael` (4 of 7; `data-mention-id` drew 2);
-- a card holding `data` and no URL as `Release plan`, `href` the URL its `data` holds (3 of 7; `data-card` drew 2, a `` without `href` 2).
-
-Where a link marks a card, both the link's target and the card's URL stay in sight, a card showing
-only its name included.
-
-Candidate entry for §The HTML dialect, if the leading spellings stand: "A mention is
-`` showing its text. A card
-holding `data` and no URL is ``, `href` the URL its `data`
-holds, showing its name." The instance it yields for the example above: `Release plan`.
+Class: the HTML dialect's spellings. Earlier entries: a card is ``,
+and HTML nests no `` in an ``, so the card's element has no room for the link beside it. The
+nearest candidate keeps the carry: "A card a link marks rides the carry, which keeps both targets in
+sight; no document Atlassian's editor writes holds one." Its instance is today's output, so the
+choice is the maintainer's: this item ends with that entry, or with a spelling the maintainer names.
### 163. Gather a corpus of real-world ADF documents from public Jira and Confluence sites, each recording where it came from and under what licence.