Shortcode round-trip engine: .md ⇄ element tree with canonical serialization #2
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/deckle#2
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What to build
The highest-risk component, as a standalone Go package with a debug surface (docs/DECISIONS.md D5): parse a Hugo content file (front matter + body) into an element tree using Hugo's vendored
parser/pageparser, and serialize the tree back to a canonical, human-readable.md(stable ordering, indentation, quoting). Nested block shortcodes and inline shortcodes inside body text must survive losslessly. Field model: flat scalar params + one body per element.Acceptance criteria
Blocked by
None - can start immediately
Agent Brief
Category: enhancement
Summary: Build the shortcode round-trip engine: a standalone Go package that parses Hugo content files (front matter + body with nested and inline shortcodes) into a typed element tree and serializes the tree back to a canonical, human-readable
.md, plus a debug endpoint that exposes the parsed tree as JSON.Note on references: the issue body cites
docs/DECISIONS.md D5; that file is not committed to the repository. The relevant decision content is restated inline here — this brief is self-contained.Current behavior:
The repository contains the walking skeleton from #1: a
harness serve --site <dir>binary that superviseshugo serverand serves an embedded SolidJS shell with an HTTP API under/api. There is no content parsing of any kind — the tool never reads.mdfiles. The sample site's content files are plain front-matter posts with no shortcodes, so no test corpus exists yet.Desired behavior:
A standalone Go package (no dependencies on the server or supervisor packages; those may depend on it) that implements a lossless, canonicalizing round-trip between Hugo content files and an element tree:
parser/pageparserpackage (importable asgithub.com/gohugoio/hugo/parser/pageparser) as the lexer rather than hand-rolling shortcode tokenization. Nested paired shortcodes (e.g. a grid containing columns containing further elements) become nested tree nodes; inline shortcodes interleaved with markdown text inside a body (e.g. a button inside a hero's text) survive as child nodes positioned within the text runs.serialize(parse(x))is byte-identical whenxis already canonical.parse(serialize(tree))is structurally identical totreefor arbitrary valid trees. Non-canonical but valid hand-written input (different quoting, param order, whitespace) parses correctly and re-emits in canonical form.Key interfaces:
/apiroutes.Acceptance criteria:
serialize(parse(x))is byte-identical for canonicalxparse(serialize(tree))is structurally identical for arbitrary trees, demonstrated by property-based/fuzz round-trip tests (Go's native fuzzing or a generator-driven property test)Out of scope:
Landing audit — PR #19 (
afk/2)Verdict: PASS (with two minor, non-blocking notes on the debug endpoint).
Checked:
ci / build-and-test (pull_request)success (2m31s). Relied on as the vouching signal; not re-run.feat:). AFK contract holds — headafk/2, body carriesCloses #2.maincleanly (no conflicts).serialize(parse(x)); structuralparse(serialize(tree))(property + native fuzz); non-canonical→canonical re-emit; quote/special-char params round-trip and newlines rejected;/api/debug/treeJSON endpoint; v1-shape corpus (grid/accordion/hero-inline)./api/debug/treeis safe (filepath.Clean+IsLocal+Join; every escape attempt rejected 400).Minor non-blocking notes (debug/diagnostic endpoint only,
internal/server/server.go):pagethat resolves to a directory (e.g.page=.) yieldsEISDIR→ 500 rather than a 4xx.err.Error(), leaking the absolute server path. Consider stat-and-reject with 404 and not echoing the raw error.Neither affects the round-trip guarantees or acceptance criteria; safe to land as-is and tighten later if desired.