Renderable Markdown Abstract Syntax Tree
npm install rmdastrmdast is an easy-to-render version of [mdast v4],
the new AST is designed to render nodes directly from AST to any platform, e.g. React.
[mdast v4]: https://github.com/syntax-tree/mdast/tree/4.0.0
sh
npm install --save rmdast
or
yarn add rmdast
`Usage
`ts
import { parse } from 'rmdast'
import { dedent } from 'extra-tags'const markdown = dedent
- 
- 
- 
const rmdast = parse(markdown)
// {
// "type": "root",
// "children": [
// {
// "type": "heading",
// "depth": 1,
// "children": [
// {
// "type": "text",
// "value": "Gallery"
// }
// ]
// },
// {
// "type": "gallery",
// "children": [
// {
// "type": "image",
// "url": "a",
// "title": null,
// "alt": ""
// },
// {
// "type": "image",
// "url": "b",
// "title": null,
// "alt": ""
// },
// {
// "type": "image",
// "url": "c",
// "title": null,
// "alt": ""
// }
// ]
// }
// ]
// }
`
ts
interface Node {
type: string
}interface Parent {
children: Node[]
}
interface ParentOf extends Parent {
children: T
}
type BlockNode =
| Root
| Paragraph
| Heading
| ThematicBreak
| Blockquote
| List
| ListItem
| Code
| Image
| Table
| TableRow
| TableCell
| LeafDirective
| ContainerDirective
| Gallery
type InlineNode =
| Text
| Emphasis
| Strong
| InlineCode
| Break
| Newline
| Link
| InlineImage
| Delete
| Footnote
| InlineFootnote
| TextDirective
type RootContent =
| UniversalBlockContent
| Gallery
type UniversalBlockContent =
| Paragraph
| Heading
| ThematicBreak
| Blockquote
| List
| Code
| Image
| Table
| LeafDirective
| ContainerDirective
type UniversalInlineContent =
| Text
| Emphasis
| Strong
| InlineCode
| Break
| Newline
| Link
| InlineImage
| Delete
| Footnote
| InlineFootnote
| TextDirective
interface Root extends Node, ParentOf {
type: 'root'
}
interface Paragraph extends Node, ParentOf {
type: 'paragraph'
}
interface Heading extends Node, ParentOf {
type: 'heading'
depth: 1 | 2 | 3 | 4 | 5 | 6
}
interface ThematicBreak extends Node {
type: 'thematicBreak'
}
interface Blockquote extends Node, ParentOf {
type: 'blockquote'
}
interface List extends Node, ParentOf {
type: 'list'
ordered: boolean | null
start: number | null
spread: boolean | null
}
interface ListItem extends Node, ParentOf {
type: 'listItem'
spread: boolean | null
checked: boolean | null
}
interface Code extends Node {
type: 'code'
value: string
lang: string | null
meta: string | null
}
interface Text extends Node {
type: 'text'
value: string
}
interface Emphasis extends Node, ParentOf {
type: 'emphasis'
}
interface Strong extends Node, ParentOf {
type: 'strong'
}
interface InlineCode extends Node {
type: 'inlineCode'
value: string
}
interface Break extends Node {
type: 'break'
}
interface Newline extends Node {
type: 'newline'
}
interface Link extends Node, ParentOf {
type: 'link'
url: string
title: string | null
}
interface Image extends Node {
type: 'image'
url: string
title: string | null
alt: string | null
}
interface InlineImage extends Node {
type: 'inlineImage'
url: string
title: string | null
alt: string | null
}
interface Table extends Node, ParentOf {
type: 'table'
header: TableRow
children: TableRow[]
}
interface TableRow extends Node, ParentOf {
type: 'tableRow'
}
interface TableCell extends Node, ParentOf {
type: 'tableCell'
}
interface Delete extends Node, ParentOf {
type: 'delete'
}
interface Footnote extends Node, ParentOf {
type: 'footnote'
}
interface InlineFootnote extends Node, ParentOf {
type: 'inlineFootnote'
}
interface TextDirective extends Node, ParentOf {
type: 'textDirective'
name: string
attributes: Record
}
interface LeafDirective extends Node, ParentOf {
type: 'leafDirective'
name: string
attributes: Record
}
interface ContainerDirective extends Node, ParentOf {
type: 'containerDirective'
name: string
attributes: Record
}
interface Gallery extends Node, ParentOf{
type: 'gallery'
}
`#### The difference between rmdast and mdast v4
All reference nodes will be converted to no reference nodes:
-
ImageReference are converted to Image.
- LinkReference are converted to Link.
- FootnoteReference are converted to Footnote.The
Footnote nodes have been renamed to InlineFootnote.The
Image nodes are now divided into two types: InlineImage and Image.The
Text nodes are now divided into two types: Text and Newline.The
Paragraph nodes with only InlineImage as a child are now parsed as Image.The top-level
ListItem nodes with Image are now parsed as Gallery.Removed
align from Table, added header.The following node types are not supported:
-
YAMLThe following node types are removed:
-
HTML
- Definition
- FootnoteDefinition
- ListContent
- TableContent
- RowContentThe following node properties are removed:
-
data
- position##### Why is there a
Gallery node type?
It is a common requirement to display multiple images with a single component,
but the syntax of Markdown determines that each image is independent,
and it is difficult to link them at the AST level.To solve this problem, rmdast adds this node type.
###### Can't this be done through directive?
Yes, but not elegant.
The following Markdown text has additional text nodes(
\n):
`markdown
:::gallery



:::
`The following Markdown text has additional blank lines:
`markdown
:::gallery


:::
`$3
`ts
function parse(text: string): AST.Root
`$3
#### builder
`ts
import * as Builder from 'rmdast/utils/builder'
`Each rmdast node has a corresponding builder.
#### is
`ts
import * as Is from 'rmdast/utils/is'
`Each rmdast node has a corresponding
is function.#### flatMap
`ts
import { flatMap } from 'rmdast/utils/flat-map'function flatMap(
node: AST.Node
, fn: (node: AST.Node) => AST.Node[]
): AST.Node[]
`#### map
`ts
import { map } from 'rmdast/utils/map'function map(
node: AST.Node
, fn: (node: AST.Node) => AST.Node
): AST.Node
`#### filter
`ts
import { filter } from 'rmdast/utils/filter'function filter(
node: AST.Node
, predicate: (node: AST.Node) => unknown
): AST.Node | undefined
`#### find
`ts
import { find } from 'rmdast/utils/find'function find(
node: AST.Node
, predicate: (node: AST.Node) => boolean
): T | undefined
`#### findAll
`ts
import { findAll } from 'rmdast/utils/find-all'function* findAll(
node: AST.Node
, predicate: (node: AST.Node) => boolean
): Iterable
`#### traverseDescendantNodes
`ts
function traverseDescendantNodes(node: AST.Node): Iterable
`#### addHelpers
`ts
import { addHelpers, addHelpersInPlace, NodeWithHelpers } from 'rmdast/utils/add-helpers'type NullOrNodeWithHelpers =
T extends null
? null
: NodeWithHelpers>
type NodeWithHelpers<
Node extends AST.Node
, Sibling extends AST.Node | null = AST.Node | null
, Parent extends AST.Node | null = AST.Node | null
> =
Node extends AST.Root
? Mixin id: string
parent: null
index: null
previousSibling: null
nextSibling: null
children: Array>
}>
: Node extends AST.Paragraph
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.Paragraph
>
>
}>
: Node extends AST.Heading
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.Heading
>
>
}>
: Node extends AST.Blockquote
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.Blockquote
>
>
}>
: Node extends AST.List
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.ListItem
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Emphasis
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Strong
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Link
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Table
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
header: NodeWithHelpers
children: Array>
}>
: Node extends AST.TableRow
? Mixin id: string
parent: NullOrNodeWithHelpers
index: Sibling extends null ? null : number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.TableCell
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Delete
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Footnote
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.Footnote
>
>
}>
: Node extends AST.InlineFootnote
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.InlineFootnote
>
>
}>
: Node extends AST.TextDirective
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.TextDirective
>
>
}>
: Node extends AST.LeafDirective
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.LeafDirective
>
>
}>
: Node extends AST.ContainerDirective
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.ContainerDirective
>
>
}>
: Node extends AST.Gallery
? Mixin id: string
parent: NullOrNodeWithHelpers
index: number
previousSibling: null
nextSibling: null
children: Array>
}>
: Mixin id: string
parent: NullOrNodeWithHelpers
index: number | null
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
}>
function addHelpers(node: T): NodeWithHelpers
function addHelpersInPlace(node: T): NodeWithHelpers
`#### removeHelpers
`ts
import { removeHelpers, removeHelpersInPlace } from 'rmdast/utils/remove-helpers'function remove
function removeHelpersInPlace(node: NodeWithHelpers): T
`#### withHelpers
`ts
import { withHelpers, withHelpersInPlace } from 'rmdast/utils/with-helpers'function withHelpers(
node: T
, fn: (node: NodeWithHelpers) => U
): U
function withHelpersInPlace(
node: T
, fn: (node: NodeWithHelpers) => U
): U
``