feat(voyage): add anchor-parser.mjs with placement validation — v4.2 Step 3

lib/parsers/anchor-parser.mjs (~190 LoC):
- parseAnchors(md) -> Anchor[] (id, target, line, snippet?, intent?)
- addAnchors(md, anchors) -> md_with_anchors
- stripAnchors(md_with_anchors) -> md (byte-identical)
- validateAnchorPlacement(md, anchors) -> errors for list-item / fenced-block / indent

Format: <!-- voyage:anchor id="ANN-NNNN" target="<slug>" line="<N>" -->
Block-level only, on its own line (col 0), blank-line separation.

Test fixture annotation-example.md with single ANN-0001 anchor — referenced by SC12 quickstart.
14 tests pass (parseAnchors, addAnchors, stripAnchors, validateAnchorPlacement).
This commit is contained in:
Kjell Tore Guttormsen 2026-05-09 12:52:46 +02:00
commit fb733ae149
3 changed files with 398 additions and 0 deletions

View file

@ -0,0 +1,27 @@
---
type: trekplan-fixture
plan_version: "1.7"
created: 2026-05-09
slug: annotation-example
---
# Sample plan with one anchor
This fixture is referenced by `docs/annotation-quickstart.md` and the SC12
machine-proxy verification (`parseAnchors` exits 0).
## Section A
A normal paragraph in section A.
<!-- voyage:anchor id="ANN-0001" target="section-b" line="20" intent="change" -->
## Section B
A paragraph in section B that the anchor above refers to. The anchor is
placed on its own line with a blank line above and below — the canonical
v4.2 placement disipline.
## Section C
Another paragraph.