oxidecomputer / oxidecomputer/prettier-plugin-asciidoc
convert a link: macro around a bare-readable URL to the bare spelling, on a substituted-byte domain model
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 1
- PR merge metrics
- No merged PRs in 30d
Description
The conversion was attempted in the replaysmall lane (Sep 5) and dropped after three fix rounds each failed adversarial re-review with fresh render divergence. This issue carries the full hazard inventory so the next attempt starts from the finished map instead of rediscovering it. The three re-review records (replaysmall-rereview.md, -rereview2.md, -rereview3.md in the sdd workspace of that date) hold the probe sets.
The conversion: link:URL[] with empty attrlist renders identically to the bare URL (both take the bare role), so one normal form (the bare spelling) should be printable wherever the re-read is provably identical.
Hazards discovered, all render-diverging and idempotent (invisible to non-render gates):
- Following byte: Ruby's bare body class [^\s[]<]* absorbs ANY following non-whitespace byte into the href (letters, punctuation, entities). Only end-of-text-at-block-level or whitespace provably terminates.
- Enclosing spans: end-of-sibling-run inside a span precedes the close delimiter; curved-quote rows close with entities whose leading & the bare body absorbs.
- Preceding byte: the unbracketed branch of convert_inline_links returns the raw match for prefix ", ', link: - the anchor is destroyed, not just mis-bounded.
- Trailing ;/: are stripped from bare hrefs and re-emitted as text; the macro form keeps them.
- THE KILLER (round 3): the byte the trailing-strip logic tests is the final byte of the SPECIALCHARACTERS-SUBSTITUTED text, not the source: a source target ending & or > substitutes to ...&/> whose final ; is then stripped - the href loses its last byte and a stray ; leaks outside the anchor. Any sound domain model must be computed over the substituted text, not source bytes.
- Interaction: the rewrite after a reflow join breaks one-pass idempotence (pass 1 joins, pass 2 rewrites) even where all renders agree.
Deliverable shape: a decision table computed over the substituted text (every row citing the vendored rx.js / substitutors.js branch), a render-comparing generated gate whose target axis is built from the SUBSTITUTED final-byte classes (the round-3 gate was sound in method - render-comparing, conversion-counting, idempotence - but its axes were derived from source bytes and could not reach hazard 5), and red-first pins for all six hazard classes. Keeping the author's link: spelling is the safe default until then (spelling-preserved cell); the confluence exception row inlineSpelling/url-macro stands as the measured record of the divergence.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with replaysmall-rereview.md, -rereview2.md, and -rereview3.md in the dated sdd workspace, then trace each cited branch in the vendored rx.js and substitutors.js files. Build the decision table and render-comparing generated gate over substituted-text final-byte classes, with red-first pins for all six hazards. Done means the gate covers the hazard inventory, preserves the safe spelling by default, and verifies render equivalence and one-pass idempotence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- testing, tooling
- Issue type
- Refactor
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100