An open API service indexing awesome lists of open source software.

https://github.com/blackglory/rmdast

🌳 Renderable Markdown Abstract Syntax Tree.
https://github.com/blackglory/rmdast

browser esm library nodejs npm-package typescript

Last synced: 5 months ago
JSON representation

🌳 Renderable Markdown Abstract Syntax Tree.

Awesome Lists containing this project

README

          

# rmdast
**R**enderable **M**ark**d**own **A**bstract **S**yntax **T**ree.

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.

[mdast v4]: https://github.com/syntax-tree/mdast/tree/4.0.0

## Install
```sh
npm install --save rmdast
# or
yarn add rmdast
```

## Usage
```ts
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
```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:
- `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`):
```markdown
:::gallery
![](a)
![](b)
![](c)
:::
```

The following Markdown text has additional blank lines:
```markdown
:::gallery
![](a)

![](b)

![](c)
:::
```

### parse
```ts
function parse(text: string): AST.Root
```

### utils
#### 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>
}>
: Node extends AST.Paragraph
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.Paragraph
>
>
}>
: Node extends AST.Heading
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.Heading
>
>
}>
: Node extends AST.Blockquote
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.Blockquote
>
>
}>
: Node extends AST.List
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.ListItem
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Emphasis
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Strong
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Link
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Table
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
header: NodeWithHelpers
children: Array>
}>
: Node extends AST.TableRow
? Mixin
index: Sibling extends null ? null : number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.TableCell
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Delete
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array>
}>
: Node extends AST.Footnote
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.Footnote
>
>
}>
: Node extends AST.InlineFootnote
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.InlineFootnote
>
>
}>
: Node extends AST.TextDirective
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.TextDirective
>
>
}>
: Node extends AST.LeafDirective
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalInlineContent
, AST.UniversalInlineContent
, AST.LeafDirective
>
>
}>
: Node extends AST.ContainerDirective
? Mixin
index: number
previousSibling: NullOrNodeWithHelpers
nextSibling: NullOrNodeWithHelpers
children: Array<
NodeWithHelpers<
AST.UniversalBlockContent
, AST.UniversalBlockContent
, AST.ContainerDirective
>
>
}>
: Node extends AST.Gallery
? Mixin
index: number
previousSibling: null
nextSibling: null
children: Array>
}>
: Mixin
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 removeHelpers(node: NodeWithHelpers): T

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
```