Documentation
¶
Overview ¶
Package adf converts between Markdown and the Atlassian Document Format (ADF), the JSON format Jira Cloud and Confluence Cloud use for rich text.
FromMarkdown always produces documents that validate against Atlassian's published ADF JSON schema: Markdown constructs that ADF cannot express in a given place are rewritten into the closest valid form (for example a heading inside a list item becomes a bold paragraph). ToMarkdown accepts any ADF document and falls back to the text content of node types it does not know.
Both directions are safe for untrusted input: they never panic, and nesting deeper than the configured limit is rejected with ErrTooDeep.
Example (Mentions) ¶
Mentions are written as @[label]. The hooks decide how people are named and resolved, for example to keep real names out of the Markdown.
package main
import (
"fmt"
"strings"
adf "github.com/nyactl/go-adf"
)
func main() {
people := map[string]string{"Person A": "5b10ac8d82e05b22cc7d4ef5"}
resolve := adf.WithMentionResolver(func(label string) (string, string, bool) {
id, ok := people[label]
return id, label, ok
})
doc, err := adf.FromMarkdown("Thanks @[Person A]!", resolve)
if err != nil {
panic(err)
}
md, err := adf.ToMarkdown(doc, adf.WithMentionText(func(accountID, text string) string {
return strings.TrimPrefix(text, "@")
}))
if err != nil {
panic(err)
}
fmt.Println(md)
}
Output: Thanks @[Person A]!
Index ¶
Examples ¶
Constants ¶
const DefaultMaxDepth = 100
DefaultMaxDepth is the nesting limit used unless WithMaxDepth sets one.
Variables ¶
var ErrTooDeep = errors.New("adf: document is nested too deeply")
ErrTooDeep is returned for documents nested deeper than the limit.
Functions ¶
func FromMarkdown ¶
func FromMarkdown(markdown string, opts ...Option) (json.RawMessage, error)
FromMarkdown converts CommonMark with the GitHub extensions for tables, strikethrough and task list checkboxes to an ADF document.
Supported: paragraphs, headings, bullet and ordered lists, fenced and indented code, block quotes, thematic breaks, tables, strong, emphasis, strikethrough, inline code, links, autolinks and, with WithMentionResolver, @[label] mentions. Images become links. Raw HTML is kept as text.
Example ¶
package main
import (
"fmt"
adf "github.com/nyactl/go-adf"
)
func main() {
doc, err := adf.FromMarkdown("Fixed in **v2.1**, see [notes](https://example.com/notes).")
if err != nil {
panic(err)
}
fmt.Println(string(doc))
}
Output: {"type":"doc","version":1,"content":[{"type":"paragraph","content":[{"type":"text","text":"Fixed in "},{"type":"text","text":"v2.1","marks":[{"type":"strong"}]},{"type":"text","text":", see "},{"type":"text","text":"notes","marks":[{"type":"link","attrs":{"href":"https://example.com/notes"}}]},{"type":"text","text":"."}]}]}
func ToMarkdown ¶
func ToMarkdown(raw json.RawMessage, opts ...Option) (string, error)
ToMarkdown renders an ADF document as Markdown. Empty or null input yields "", and a JSON string (which some Jira fields still hold instead of a document) is returned as is. Unknown node types fall back to their text content.
Example ¶
package main
import (
"encoding/json"
"fmt"
adf "github.com/nyactl/go-adf"
)
func main() {
doc := json.RawMessage(`{"type":"doc","version":1,"content":[
{"type":"heading","attrs":{"level":2},"content":[{"type":"text","text":"Steps"}]},
{"type":"orderedList","content":[
{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"Run "},{"type":"text","text":"make test","marks":[{"type":"code"}]}]}]},
{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"Ship it"}]}]}]}]}`)
md, err := adf.ToMarkdown(doc)
if err != nil {
panic(err)
}
fmt.Println(md)
}
Output: ## Steps 1. Run `make test` 2. Ship it
Types ¶
type MentionError ¶
type MentionError struct {
Label string
}
MentionError is returned by FromMarkdown when the mention resolver does not know a @[label].
func (*MentionError) Error ¶
func (e *MentionError) Error() string
type Node ¶
type Node struct {
Type string `json:"type"`
Version int `json:"version,omitempty"`
Attrs map[string]any `json:"attrs,omitempty"`
Content []Node `json:"content,omitempty"`
Text string `json:"text,omitempty"`
Marks []Mark `json:"marks,omitempty"`
}
Node is an ADF node.
type Option ¶
type Option func(*config)
Option configures a conversion. Options that do not apply to a direction are ignored.
func WithMaxDepth ¶
WithMaxDepth sets the nesting limit for both directions.
func WithMentionResolver ¶
WithMentionResolver makes FromMarkdown turn @[label] into mention nodes. The resolver returns the account ID and the display name to store; when it reports false, FromMarkdown fails with a *MentionError. Without a resolver, @[label] stays plain text.
func WithMentionText ¶
WithMentionText sets how ToMarkdown names a mentioned person. It receives the account ID and the text stored with the mention (usually "@Name") and returns the label written as @[label]. By default the stored text is used.