This document describes how Markdown elements (represented as goldmark AST nodes) map to Atlassian Document Format (ADF) nodes.
| Goldmark | ADF | Notes |
|---|---|---|
ast.KindDocument |
doc |
Root wrapper with version: 1 |
Goldmark AST:
type Document struct {
BaseBlock
}ADF Output:
{
"version": 1,
"type": "doc",
"content": [...]
}| Goldmark | ADF | Notes |
|---|---|---|
ast.KindParagraph |
paragraph |
Container for inline content |
Goldmark AST:
type Paragraph struct {
BaseBlock
}ADF Output:
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Hello world" }
]
}| Goldmark | ADF | Notes |
|---|---|---|
ast.KindHeading |
heading |
Level 1-6, stored in attrs.level |
Goldmark AST:
type Heading struct {
BaseBlock
Level int // 1-6
}ADF Output:
{
"type": "heading",
"attrs": { "level": 1 },
"content": [
{ "type": "text", "text": "Heading Text" }
]
}| Goldmark | ADF | Notes |
|---|---|---|
ast.KindBlockquote |
blockquote |
Contains paragraphs, lists, code blocks |
Goldmark AST:
type Blockquote struct {
BaseBlock
}ADF Output:
{
"type": "blockquote",
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Quoted text" }]
}
]
}Allowed Content: paragraph, bulletList, orderedList, codeBlock, mediaGroup, mediaSingle
| Goldmark | ADF | Notes |
|---|---|---|
ast.KindCodeBlock |
codeBlock |
Indented code block |
ast.KindFencedCodeBlock |
codeBlock |
Fenced with optional language |
Goldmark AST:
type FencedCodeBlock struct {
BaseBlock
Info *Text // Language identifier
}
// Access language: n.Language(source)ADF Output:
{
"type": "codeBlock",
"attrs": { "language": "javascript" },
"content": [
{ "type": "text", "text": "var foo = 'bar';" }
]
}Note: ADF code blocks contain text nodes without marks. Language is optional.
| Goldmark | ADF | Notes |
|---|---|---|
ast.KindThematicBreak |
rule |
---, ***, or ___ in Markdown |
Goldmark AST:
type ThematicBreak struct {
BaseBlock
}ADF Output:
{
"type": "rule"
}| Goldmark | ADF | Notes |
|---|---|---|
ast.KindList (unordered) |
bulletList |
Uses -, *, or + marker |
ast.KindList (ordered) |
orderedList |
Uses 1. style markers |
ast.KindListItem |
listItem |
Child of either list type |
Goldmark AST:
type List struct {
BaseBlock
Marker byte // '-', '*', '+', ')' or '.'
IsTight bool
Start int // Starting number for ordered lists
}
func (l *List) IsOrdered() bool // Check if orderedADF bulletList:
{
"type": "bulletList",
"content": [
{
"type": "listItem",
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Item 1" }]
}
]
}
]
}ADF orderedList:
{
"type": "orderedList",
"attrs": { "order": 1 },
"content": [
{
"type": "listItem",
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "First item" }]
}
]
}
]
}listItem Allowed Content: paragraph, bulletList, orderedList, codeBlock, mediaSingle
| Goldmark | ADF | Notes |
|---|---|---|
ast.KindText |
text |
Plain text content |
Goldmark AST:
type Text struct {
BaseInline
Segment textm.Segment // Position in source
}
// Access value: n.Value(source) or segment.Value(source)
// Check line breaks: n.HardLineBreak(), n.SoftLineBreak()ADF Output:
{
"type": "text",
"text": "Hello world"
}With marks:
{
"type": "text",
"text": "Bold text",
"marks": [{ "type": "strong" }]
}| Goldmark | ADF | Notes |
|---|---|---|
ast.KindText with HardLineBreak() |
hardBreak |
Two spaces + newline or \ + newline |
Goldmark: Check text.HardLineBreak() == true
ADF Output:
{
"type": "hardBreak"
}| Goldmark | ADF | Notes |
|---|---|---|
ast.KindEmphasis (Level=1) |
em mark |
*text* or _text_ |
ast.KindEmphasis (Level=2) |
strong mark |
**text** or __text__ |
Goldmark AST:
type Emphasis struct {
BaseInline
Level int // 1 = italic, 2 = bold
}ADF Output (emphasis):
{
"type": "text",
"text": "italic text",
"marks": [{ "type": "em" }]
}ADF Output (strong):
{
"type": "text",
"text": "bold text",
"marks": [{ "type": "strong" }]
}Combined:
{
"type": "text",
"text": "bold and italic",
"marks": [{ "type": "strong" }, { "type": "em" }]
}| Goldmark | ADF | Notes |
|---|---|---|
ast.KindCodeSpan |
code mark |
`code` in Markdown |
Goldmark AST:
type CodeSpan struct {
BaseInline
}
// Children are Text nodes with raw contentADF Output:
{
"type": "text",
"text": "inline code",
"marks": [{ "type": "code" }]
}Constraint: code mark can only combine with link mark, no other marks.
| Goldmark | ADF | Notes |
|---|---|---|
ast.KindLink |
link mark |
[text](url) syntax |
ast.KindAutoLink |
link mark |
Auto-detected URLs |
Goldmark AST:
type Link struct {
BaseInline
Destination []byte // URL
Title []byte // Optional title
}ADF Output:
{
"type": "text",
"text": "Click here",
"marks": [
{
"type": "link",
"attrs": {
"href": "https://example.com",
"title": "Example Site"
}
}
]
}| Goldmark | ADF | Notes |
|---|---|---|
ast.KindImage |
mediaSingle + media |
Complex - requires special handling |
Goldmark AST:
type Image struct {
BaseInline
Destination []byte // Image URL
Title []byte
}
// Alt text is in child Text nodesADF Output (external URL):
Images in ADF are complex. For external URLs, you may need to use inlineCard or handle via media services:
{
"type": "mediaSingle",
"attrs": { "layout": "center" },
"content": [
{
"type": "media",
"attrs": {
"type": "external",
"url": "https://example.com/image.png"
}
}
]
}Alternative: Convert to link if media services aren't available:
{
"type": "text",
"text": "alt text",
"marks": [{ "type": "link", "attrs": { "href": "https://example.com/image.png" } }]
}These require the GFM extension to be enabled in goldmark.
| Goldmark | ADF | Notes |
|---|---|---|
extension.KindStrikethrough |
strike mark |
~~text~~ syntax |
ADF Output:
{
"type": "text",
"text": "deleted text",
"marks": [{ "type": "strike" }]
}| Goldmark | ADF | Notes |
|---|---|---|
extension.KindTable |
table |
Table container |
extension.KindTableHeader |
tableRow with tableHeader cells |
First row |
extension.KindTableRow |
tableRow with tableCell cells |
Body rows |
extension.KindTableCell |
tableCell or tableHeader |
Individual cells |
ADF Output:
{
"type": "table",
"attrs": {
"isNumberColumnEnabled": false,
"layout": "center"
},
"content": [
{
"type": "tableRow",
"content": [
{
"type": "tableHeader",
"attrs": {},
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Header 1" }]
}
]
}
]
},
{
"type": "tableRow",
"content": [
{
"type": "tableCell",
"attrs": {},
"content": [
{
"type": "paragraph",
"content": [{ "type": "text", "text": "Cell 1" }]
}
]
}
]
}
]
}Table Cell Attributes:
background: Hex color codecolspan: Number of columns to spanrowspan: Number of rows to spancolwidth: Array of column widths in pixels
| Mark | Purpose | Attributes |
|---|---|---|
strong |
Bold text | None |
em |
Italic text | None |
strike |
Strikethrough | None |
underline |
Underlined text | None |
code |
Inline code | None |
link |
Hyperlink | href (required), title |
subsup |
Subscript/superscript | type: "sub" or "sup" |
textColor |
Colored text | color: hex code |
These ADF nodes don't have standard Markdown equivalents:
| ADF Node | Purpose | Possible Mapping |
|---|---|---|
panel |
Highlighted content box | Could map from custom syntax or admonitions |
expand |
Collapsible section | Could map from <details> HTML |
emoji |
Emoji characters | Could detect :shortcode: patterns |
mention |
User mentions | Could detect @username patterns |
status |
Status badges | No standard equivalent |
date |
Date picker value | No standard equivalent |
inlineCard |
Rich link preview | Could upgrade from regular links |
Unlike HTML where tags nest, ADF marks are a flat array on text nodes. When traversing emphasis/link nodes:
- Track active marks in a stack
- When reaching a text node, apply all accumulated marks
- Pop marks when leaving emphasis/link nodes
Some ADF constraints to handle:
- Blockquote content: Only allows paragraph, lists, codeBlock, media - not headings
- ListItem content: Text must be wrapped in paragraph
- Code marks: Cannot combine with most other marks (only link)
- Panel content: No marks allowed on paragraph/heading children
Goldmark's ast.Text nodes include:
HardLineBreak(): Convert to ADFhardBreakSoftLineBreak(): Usually becomes space in outputIsRaw(): Used in code blocks
Access text value: segment.Value(source) where source is the original Markdown bytes.