rmdast
v8.0.4
Published
Renderable Markdown Abstract Syntax Tree
Downloads
9
Readme
rmdast
Renderable Markdown Abstract Syntax Tree.
rmdast 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.
Install
npm install --save rmdast
# or
yarn add rmdast
Usage
import { parse } from 'rmdast'
import { dedent } from 'extra-tags'
const markdown = dedent`
# Gallery
- ![](a)
- ![](b)
- ![](c)
`
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": ""
// }
// ]
// }
// ]
// }
API
AST
interface Node {
type: string
}
interface Parent {
children: Node[]
}
interface ParentOf<T extends Node[]> 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<RootContent[]> {
type: 'root'
}
interface Paragraph extends Node, ParentOf<UniversalInlineContent[]> {
type: 'paragraph'
}
interface Heading extends Node, ParentOf<UniversalInlineContent[]> {
type: 'heading'
depth: 1 | 2 | 3 | 4 | 5 | 6
}
interface ThematicBreak extends Node {
type: 'thematicBreak'
}
interface Blockquote extends Node, ParentOf<UniversalBlockContent[]> {
type: 'blockquote'
}
interface List extends Node, ParentOf<ListItem[]> {
type: 'list'
ordered: boolean | null
start: number | null
spread: boolean | null
}
interface ListItem extends Node, ParentOf<UniversalBlockContent[]> {
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<UniversalInlineContent[]> {
type: 'emphasis'
}
interface Strong extends Node, ParentOf<UniversalInlineContent[]> {
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<UniversalInlineContent[]> {
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<TableRow[]> {
type: 'table'
header: TableRow
children: TableRow[]
}
interface TableRow extends Node, ParentOf<TableCell[]> {
type: 'tableRow'
}
interface TableCell extends Node, ParentOf<UniversalInlineContent[]> {
type: 'tableCell'
}
interface Delete extends Node, ParentOf<UniversalInlineContent[]> {
type: 'delete'
}
interface Footnote extends Node, ParentOf<UniversalBlockContent[]> {
type: 'footnote'
}
interface InlineFootnote extends Node, ParentOf<UniversalInlineContent[]> {
type: 'inlineFootnote'
}
interface TextDirective extends Node, ParentOf<UniversalInlineContent[]> {
type: 'textDirective'
name: string
attributes: Record<string, string>
}
interface LeafDirective extends Node, ParentOf<UniversalInlineContent[]> {
type: 'leafDirective'
name: string
attributes: Record<string, string>
}
interface ContainerDirective extends Node, ParentOf<UniversalBlockContent[]> {
type: 'containerDirective'
name: string
attributes: Record<string, string>
}
interface Gallery extends Node, ParentOf<Image[]>{
type: 'gallery'
}
The difference between rmdast and mdast v4
All reference nodes will be converted to no reference nodes:
ImageReference
are converted toImage
.LinkReference
are converted toLink
.FootnoteReference
are converted toFootnote
.
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:
YAML
The following node types are removed:
HTML
Definition
FootnoteDefinition
ListContent
TableContent
RowContent
The 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
):
:::gallery
![](a)
![](b)
![](c)
:::
The following Markdown text has additional blank lines:
:::gallery
![](a)
![](b)
![](c)
:::
parse
function parse(text: string): AST.Root
utils
builder
import * as Builder from 'rmdast/utils/builder'
Each rmdast node has a corresponding builder.
is
import * as Is from 'rmdast/utils/is'
Each rmdast node has a corresponding is
function.
flatMap
import { flatMap } from 'rmdast/utils/flat-map'
function flatMap(
node: AST.Node
, fn: (node: AST.Node) => AST.Node[]
): AST.Node[]
map
import { map } from 'rmdast/utils/map'
function map(
node: AST.Node
, fn: (node: AST.Node) => AST.Node
): AST.Node
filter
import { filter } from 'rmdast/utils/filter'
function filter(
node: AST.Node
, predicate: (node: AST.Node) => unknown
): AST.Node | undefined
find
import { find } from 'rmdast/utils/find'
function find<T extends AST.Node>(
node: AST.Node
, predicate: (node: AST.Node) => boolean
): T | undefined
findAll
import { findAll } from 'rmdast/utils/find-all'
function* findAll<T extends AST.Node>(
node: AST.Node
, predicate: (node: AST.Node) => boolean
): Iterable<T>
traverseDescendantNodes
function traverseDescendantNodes(node: AST.Node): Iterable<AST.Node>
addHelpers
import { addHelpers, addHelpersInPlace, NodeWithHelpers } from 'rmdast/utils/add-helpers'
type NullOrNodeWithHelpers<T extends AST.Node | null> =
T extends null
? null
: NodeWithHelpers<NonNullable<T>>
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<Node, {
id: string
parent: null
index: null
previousSibling: null
nextSibling: null
children: Array<NodeWithHelpers<AST.RootContent, AST.RootContent, AST.Root>>
}>
: Node extends AST.Paragraph
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.Paragraph
>
>
}>
: Node extends AST.Heading
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.Heading
>
>
}>
: Node extends AST.Blockquote
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.Blockquote
>
>
}>
: Node extends AST.List
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<NodeWithHelpers<AST.ListItem, AST.ListItem, AST.List>>
}>
: Node extends AST.ListItem
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<NodeWithHelpers<AST.UniversalBlockContent, AST.UniversalBlockContent, AST.ListItem>>
}>
: Node extends AST.Emphasis
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<NodeWithHelpers<AST.UniversalInlineContent, AST.UniversalInlineContent, AST.Emphasis>>
}>
: Node extends AST.Strong
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<NodeWithHelpers<AST.UniversalInlineContent, AST.UniversalInlineContent, AST.Strong>>
}>
: Node extends AST.Link
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<NodeWithHelpers<AST.UniversalInlineContent, AST.UniversalInlineContent, AST.Link>>
}>
: Node extends AST.Table
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
header: NodeWithHelpers<AST.TableRow, null, AST.Table>
children: Array<NodeWithHelpers<AST.TableRow, AST.TableRow, AST.Table>>
}>
: Node extends AST.TableRow
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: Sibling extends null ? null : number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<NodeWithHelpers<AST.TableCell, AST.TableCell, AST.TableRow>>
}>
: Node extends AST.TableCell
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<NodeWithHelpers<AST.UniversalInlineContent, AST.UniversalInlineContent, AST.TableCell>>
}>
: Node extends AST.Delete
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<NodeWithHelpers<AST.UniversalInlineContent, AST.UniversalInlineContent, AST.Delete>>
}>
: Node extends AST.Footnote
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.Footnote
>
>
}>
: Node extends AST.InlineFootnote
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.InlineFootnote
>
>
}>
: Node extends AST.TextDirective
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.TextDirective
>
>
}>
: Node extends AST.LeafDirective
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.LeafDirective
>
>
}>
: Node extends AST.ContainerDirective
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.ContainerDirective
>
>
}>
: Node extends AST.Gallery
? Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<AST.Root>
index: number
previousSibling: null
nextSibling: null
children: Array<NodeWithHelpers<AST.Image, AST.Image, AST.Gallery>>
}>
: Mixin<Node, {
id: string
parent: NullOrNodeWithHelpers<Parent>
index: number | null
previousSibling: NullOrNodeWithHelpers<Sibling>
nextSibling: NullOrNodeWithHelpers<Sibling>
}>
function addHelpers<T extends AST.Node>(node: T): NodeWithHelpers<T>
function addHelpersInPlace<T extends AST.Node>(node: T): NodeWithHelpers<T>
removeHelpers
import { removeHelpers, removeHelpersInPlace } from 'rmdast/utils/remove-helpers'
function remove
function removeHelpersInPlace<T extends AST.Node>(node: NodeWithHelpers<T>): T
withHelpers
import { withHelpers, withHelpersInPlace } from 'rmdast/utils/with-helpers'
function withHelpers<T extends AST.Node, U>(
node: T
, fn: (node: NodeWithHelpers<T>) => U
): U
function withHelpersInPlace<T extends AST.Node, U>(
node: T
, fn: (node: NodeWithHelpers<T>) => U
): U