Bidirectional converter between Markdown and Atlassian Document Format (ADF) with built-in support for mentions, emojis, and smart links.
- Bidirectional conversion - Convert Markdown to ADF and ADF back to Markdown
- Mentions - Parse
@usernamesyntax and convert to/from ADF mention nodes - Emojis - Support for
:shortcode:emoji syntax with Unicode mapping - Smart Links - Automatic detection of Jira/Confluence URLs as inline/block cards
- Full Markdown support - Headings, lists, task lists, tables, code blocks, blockquotes, and more
- ADF validation - JSON schema validation with semantic checks
- TypeScript - Full type definitions included
- Dual build - ESM and CommonJS outputs
npm install @faulander/md2adfimport { markdownToAdf } from '@faulander/md2adf';
const markdown = `
# Hello World
This is a **bold** statement with a :smile: emoji.
- Task 1
- [x] Task 2 (done)
Check out [PROJ-123](https://company.atlassian.net/browse/PROJ-123)
`;
const adf = markdownToAdf(markdown);
console.log(JSON.stringify(adf, null, 2));import { adfToMarkdown } from '@faulander/md2adf';
const adf = {
version: 1,
type: 'doc',
content: [
{
type: 'paragraph',
content: [
{ type: 'text', text: 'Hello ', marks: [{ type: 'strong' }] },
{ type: 'text', text: 'World!' }
]
}
]
};
const markdown = adfToMarkdown(adf);
console.log(markdown); // **Hello** World!Converts a Markdown string to an ADF document.
import { markdownToAdf } from '@faulander/md2adf';
const adf = markdownToAdf('# Hello World', {
enableSmartLinks: true,
mentionResolver: (username) => ({ id: `user-${username}`, text: `@${username}` }),
smartLinkResolver: (url) => 'inline' | 'block' | 'link'
});Options:
enableSmartLinks- Enable automatic smart link detection (default:true)mentionResolver- Custom function to resolve@mentionsto user IDssmartLinkResolver- Custom function to determine link type
Converts an ADF document to a Markdown string.
import { adfToMarkdown } from '@faulander/md2adf';
const markdown = adfToMarkdown(adfDocument, {
mentionFormatter: (id, text) => `@${text || id}`
});Options:
mentionFormatter- Custom function to format mentions in Markdown output
Smart links automatically convert Atlassian URLs to inline or block cards.
import {
detectSmartLinkType,
isAtlassianUrl,
createSmartLinkResolver
} from '@faulander/md2adf';
// Detect link type
detectSmartLinkType('https://company.atlassian.net/browse/PROJ-123'); // 'inline'
detectSmartLinkType('https://company.atlassian.net/wiki/spaces/DOC'); // 'block'
detectSmartLinkType('https://example.com'); // 'link'
// Create custom resolver
const resolver = createSmartLinkResolver({
inlineDomains: ['github.com'],
blockDomains: ['notion.so'],
fallbackToAtlassianDetection: true
});import {
createMentionResolver,
createMentionFormatter,
parseMention
} from '@faulander/md2adf';
// Create resolver with user mapping
const resolver = createMentionResolver({
'johndoe': 'user-123',
'janedoe': 'user-456'
});
// Create custom formatter
const formatter = createMentionFormatter('linked'); // @[display](id)
// Parse mention strings
parseMention('@johndoe'); // { username: 'johndoe' }
parseMention('@[John Doe](user-123)'); // { displayName: 'John Doe', id: 'user-123' }import {
getEmojiUnicode,
getEmojiShortname,
isValidEmoji,
replaceEmojiShortnames
} from '@faulander/md2adf';
getEmojiUnicode('smile'); // 'π'
getEmojiShortname('π'); // 'smile'
isValidEmoji('thumbsup'); // true
replaceEmojiShortnames('Hello :wave:!'); // 'Hello π!'import { validateADFDocument, assertValidADF } from '@faulander/md2adf';
// Validate and get errors
const result = validateADFDocument(adf);
if (!result.valid) {
console.error(result.errors);
}
// Assert valid (throws on invalid)
assertValidADF(adf);| Syntax | Example | ADF Node Type |
|---|---|---|
| Headings | # H1 to ###### H6 |
heading |
| Bold | **bold** |
strong mark |
| Italic | *italic* |
em mark |
| Strikethrough | ~~strike~~ |
strike mark |
| Inline code | `code` |
code mark |
| Links | [text](url) |
link mark |
| Images |  |
mediaSingle |
| Bullet lists | - item |
bulletList |
| Ordered lists | 1. item |
orderedList |
| Task lists | - [ ] todo |
taskList |
| Blockquotes | > quote |
blockquote |
| Code blocks | ```lang |
codeBlock |
| Tables | | a | b | |
table |
| Horizontal rule | --- |
rule |
| Mentions | @username |
mention |
| Emojis | :smile: |
emoji |
The package exports comprehensive TypeScript types:
import type {
ADFDocument,
ADFNode,
ADFMark,
MarkdownToADFOptions,
ADFToMarkdownOptions,
MentionResolver,
SmartLinkResolver
} from '@faulander/md2adf';import {
ConversionError,
InvalidMarkdownError,
InvalidADFError,
SchemaValidationError
} from '@faulander/md2adf';
try {
const adf = markdownToAdf(markdown);
} catch (error) {
if (error instanceof InvalidMarkdownError) {
console.error('Invalid Markdown:', error.message);
}
}# Install dependencies
npm install
# Build
npm run build
# Run tests
npm test
# Lint
npm run lint
# Format
npm run formatMIT - Harald Fauland (@faulander)