rescript-mfm

ReScript bindings for mfm-js - An MFM (Misskey Flavored Markdown) parser implementation.

Installation

npm install rescript-mfm mfm-js
# or
yarn add rescript-mfm mfm-js

Add rescript-mfm to your bsconfig.json or rescript.json:

{
  "bs-dependencies": ["rescript-mfm"]
}

What is MFM?

MFM (Misskey Flavored Markdown) is a markup language used in Misskey and other Fediverse platforms. It extends standard Markdown with additional features like:

Quick Start

// Parse MFM text into nodes
let text = "Hello **world**! :emoji: @user@example.com #hashtag"
let nodes = Mfm.parse(text)

// Parse simple MFM (only emoji and text)
let simpleText = "I like the hot soup :soup:"
let simpleNodes = Mfm.parseSimple(simpleText)

// Convert nodes back to MFM text
let reconstructed = Mfm.toString(nodes)

// Extract plain text
let plainText = Mfm.extractText(nodes)

Usage Examples

Parsing with Options

// Parse with custom nesting limit (default is 20)
let nodes = Mfm.parse(~nestLimit=10, text)

Inspecting Nodes

// Iterate over all nodes in the tree
Mfm.inspect(nodes, node => {
  Console.log(node.type_)
})

// Extract specific node types
let mentions = Mfm.extract(nodes, node => 
  node.type_ === "mention"
)

Working with Specific Node Types

// Get all mentions from parsed MFM
let getAllMentions = (nodes) => {
  Mfm.getAllOfType(nodes, "mention")
}

// Check if MFM contains hashtags
let hasHashtags = (nodes) => {
  Mfm.containsType(nodes, "hashtag")
}

// Get all emoji codes
let getEmojis = (nodes) => {
  Mfm.getAllOfType(nodes, "emojiCode")
}

Example: Extracting Data from Nodes

let extractMentionData = (node: Mfm.node) => {
  if node.type_ === "mention" {
    switch node.props {
    | Some(props) => {
        let username = Dict.get(props, "username")
          ->Option.flatMap(JSON.Decode.string)
        let host = Dict.get(props, "host")
          ->Option.flatMap(JSON.Decode.string)
        let acct = Dict.get(props, "acct")
          ->Option.flatMap(JSON.Decode.string)
        
        (username, host, acct)
      }
    | None => (None, None, None)
    }
  } else {
    (None, None, None)
  }
}

let mentions = Mfm.getAllOfType(nodes, "mention")
let mentionData = mentions->Array.map(extractMentionData)

API Reference

Parse Functions

Stringify Functions

Inspection Functions

Utility Functions

Node Types

All MFM nodes have this structure:

type node = {
  @as("type") type_: string,
  props?: Dict.t<JSON.t>,
  children?: array<node>,
}

Block Node Types

Inline Node Types

Design Pattern

This package follows the wrapper/bindings pattern similar to other ReScript FFI libraries:

Examples

See the examples directory for more usage examples.

License

MIT

Related Projects