Skip to main content

jc_adf/
lib.rs

1//! Markdown ↔ Atlassian Document Format (ADF) converter.
2//!
3//! Pure functions, no I/O. Load-bearing for every read and write path in
4//! `jc`.
5//!
6//! ## Coverage
7//!
8//! - **Full round-trip:** paragraphs, headings (H1–H6), text marks (strong,
9//!   em, code, strike), links, bullet and ordered lists (including
10//!   tight-list inline handling), fenced code blocks with language hints,
11//!   blockquotes, horizontal rules, hard breaks, GFM tables (header + body,
12//!   inline marks preserved; column alignment is dropped because ADF has
13//!   no per-column alignment).
14//! - **Read-only:** `@user` mentions (rendered as `@name`), `mediaSingle`
15//!   images (rendered as `![alt](attachment:ID)` sidecar references),
16//!   `inlineCard`, `emoji`.
17//! - **Lossless escape hatch:** any ADF node type the converter doesn't
18//!   explicitly handle is rendered as a ` ```adf:<type>` fenced code block
19//!   whose body is the raw node JSON. When that markdown is re-parsed by
20//!   [`to_adf`], the fenced block re-inflates verbatim. Fence length is
21//!   chosen dynamically so nested backticks in the serialized JSON can't
22//!   break out of the block.
23//!
24//! ## Deferred
25//!
26//! Write-path implementations for: generated table of contents, typed
27//! user mentions (requires an async accountId lookup hook), and the
28//! inline-image upload pipeline. All of these round-trip losslessly
29//! via the escape hatch; they just lack friendly markdown syntax.
30
31pub mod from_adf;
32pub mod to_adf;
33
34/// ADF is kept as `serde_json::Value` internally. That keeps the converter
35/// small and trivially extensible — new node types are one match arm away.
36pub type AdfDocument = serde_json::Value;
37
38pub use from_adf::to_markdown;
39pub use to_adf::to_adf;