Skip to content

faulander/md2adf

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

4 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

@faulander/md2adf

Bidirectional converter between Markdown and Atlassian Document Format (ADF) with built-in support for mentions, emojis, and smart links.

Features

  • Bidirectional conversion - Convert Markdown to ADF and ADF back to Markdown
  • Mentions - Parse @username syntax 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

Installation

npm install @faulander/md2adf

Quick Start

Markdown to ADF

import { 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));

ADF to Markdown

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!

API Reference

Core Functions

markdownToAdf(markdown, options?)

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 @mentions to user IDs
  • smartLinkResolver - Custom function to determine link type

adfToMarkdown(adf, options?)

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

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
});

Mentions

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' }

Emojis

import {
  getEmojiUnicode,
  getEmojiShortname,
  isValidEmoji,
  replaceEmojiShortnames
} from '@faulander/md2adf';

getEmojiUnicode('smile'); // 'πŸ˜„'
getEmojiShortname('πŸ˜„'); // 'smile'
isValidEmoji('thumbsup'); // true
replaceEmojiShortnames('Hello :wave:!'); // 'Hello πŸ‘‹!'

Validation

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);

Supported Markdown Syntax

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 ![alt](url) 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

Types

The package exports comprehensive TypeScript types:

import type {
  ADFDocument,
  ADFNode,
  ADFMark,
  MarkdownToADFOptions,
  ADFToMarkdownOptions,
  MentionResolver,
  SmartLinkResolver
} from '@faulander/md2adf';

Error Handling

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);
  }
}

Development

# Install dependencies
npm install

# Build
npm run build

# Run tests
npm test

# Lint
npm run lint

# Format
npm run format

License

MIT - Harald Fauland (@faulander)

About

The repository implements bidirectional conversion between Markdown and Atlassian Document Format (ADF)

Topics

Resources

Stars

Watchers

Forks

Contributors