unified

Learn/Recipe/Build a syntax tree

How to build a syntax tree

It’s often useful to build new (fragments of) syntax trees when adding or replacing content. It’s possible to create trees with plain object and array literals (JSON) or programmatically with a small utility. Finally it’s even possible to use JSX to build trees.

JSON

The most basic way to create a tree is with plain object and arrays. To prevent type errors, this can be checked with the types for the given syntax tree language, in this case mdast:

import type {Root} from 'mdast'

// Note the `: Root` is a TypeScript annotation.
// For plain JavaScript, remove it (and the import).
const mdast: Root = {
  type: 'root',
  children: [
    {
      type: 'paragraph',
      children: [
        {
          type: 'text',
          value: 'example'
        }
      ]
    }
  ]
}
(alias) interface Root
import Root

Document fragment or a whole document.

Should be used as the root of a tree and must not be used as a child.

const mdast: Root
(alias) interface Root
import Root

Document fragment or a whole document.

Should be used as the root of a tree and must not be used as a child.

(property) Root.type: "root"

Node type of mdast root.

(property) Parent.children: RootContent[]

List of children.

(property) Paragraph.type: "paragraph"

Node type of mdast paragraph.

(property) Paragraph.children: PhrasingContent[]

Children of paragraph.

(property) Text.type: "text"

Node type of mdast text.

(property) Literal.value: string

Plain-text value.

unist-builder

It’s also possible to build trees with unist-builder. It allows a more concise, “hyperscript” like syntax (which is also like React.createElement):

/**
 * @import {Root} from 'mdast'
 */

import {u} from 'unist-builder'

/** @type {Root} */
const mdast = u('root', [
  u('paragraph', [
    u('text', 'example')
  ])
])
(alias) function u<T extends string, P extends Record<string, unknown>, C extends Node[]>(type: T): {
    type: T;
} (+5 overloads)
import u
const mdast: Root
  • @type {Root}
(alias) u<"root", Record<string, unknown>, {
    type: "paragraph";
    children: {
        type: "text";
        value: string;
    }[];
}[]>(type: "root", children: {
    type: "paragraph";
    children: {
        type: "text";
        value: string;
    }[];
}[]): {
    type: "root";
    children: {
        type: "paragraph";
        children: {
            type: "text";
            value: string;
        }[];
    }[];
} (+5 overloads)
import u
(alias) u<"paragraph", Record<string, unknown>, {
    type: "text";
    value: string;
}[]>(type: "paragraph", children: {
    type: "text";
    value: string;
}[]): {
    type: "paragraph";
    children: {
        type: "text";
        value: string;
    }[];
} (+5 overloads)
import u
(alias) u<"text", Record<string, unknown>, Node[]>(type: "text", value: string): {
    type: "text";
    value: string;
} (+5 overloads)
import u

hastscript

When working with hast (HTML), hastscript can be used.

import {h, s} from 'hastscript'

console.log(
  h('div#some-id.foo', [
    h('span', 'some text'),
    h('input', {type: 'text', value: 'foo'}),
    h('a.alpha.bravo.charlie', {download: true}, 'delta')
  ])
)

// SVG:
console.log(
  s('svg', {viewBox: '0 0 500 500', xmlns: 'http://www.w3.org/2000/svg'}, [
    s('title', 'SVG `<circle>` element'),
    s('circle', {cx: 120, cy: 120, r: 100})
  ])
)
(alias) namespace h
(alias) const h: {
    (selector?: null | undefined, ...children: Child[]): Root;
    (selector: string, properties: Properties, ...children: Child[]): Element;
    (selector: string, ...children: Child[]): Element;
}
import h
  • @type {ReturnType}
(alias) namespace s
(alias) const s: {
    (selector?: null | undefined, ...children: Child[]): Root;
    (selector: string, properties: Properties, ...children: Child[]): Element;
    (selector: string, ...children: Child[]): Element;
}
import s
  • @type {ReturnType}
var console: Console
(method) console.Console.log(...data: any[]): void
(alias) h(selector: string, ...children: Child[]): Element (+2 overloads)
import h

Hyperscript compatible DSL for creating virtual hast trees.

  • @overload
  • @overload
  • @overload
  • @param selector Selector.
  • @param properties Properties (or first child) (default: undefined).
  • @param children Children.
  • @returns Result.
(alias) h(selector: string, ...children: Child[]): Element (+2 overloads)
import h

Hyperscript compatible DSL for creating virtual hast trees.

  • @overload
  • @overload
  • @overload
  • @param selector Selector.
  • @param properties Properties (or first child) (default: undefined).
  • @param children Children.
  • @returns Result.
(alias) h(selector: string, properties: Properties, ...children: Child[]): Element (+2 overloads)
import h

Hyperscript compatible DSL for creating virtual hast trees.

  • @overload
  • @overload
  • @overload
  • @param selector Selector.
  • @param properties Properties (or first child) (default: undefined).
  • @param children Children.
  • @returns Result.
(property) type: string
(property) value: string
(alias) h(selector: string, properties: Properties, ...children: Child[]): Element (+2 overloads)
import h

Hyperscript compatible DSL for creating virtual hast trees.

  • @overload
  • @overload
  • @overload
  • @param selector Selector.
  • @param properties Properties (or first child) (default: undefined).
  • @param children Children.
  • @returns Result.
(property) download: true
var console: Console
(method) console.Console.log(...data: any[]): void
(alias) s(selector: string, properties: Properties, ...children: Child[]): Element (+2 overloads)
import s

Hyperscript compatible DSL for creating virtual hast trees.

  • @overload
  • @overload
  • @overload
  • @param selector Selector.
  • @param properties Properties (or first child) (default: undefined).
  • @param children Children.
  • @returns Result.
(property) viewBox: string
(property) xmlns: string
(alias) s(selector: string, ...children: Child[]): Element (+2 overloads)
import s

Hyperscript compatible DSL for creating virtual hast trees.

  • @overload
  • @overload
  • @overload
  • @param selector Selector.
  • @param properties Properties (or first child) (default: undefined).
  • @param children Children.
  • @returns Result.
(alias) s(selector: string, properties: Properties, ...children: Child[]): Element (+2 overloads)
import s

Hyperscript compatible DSL for creating virtual hast trees.

  • @overload
  • @overload
  • @overload
  • @param selector Selector.
  • @param properties Properties (or first child) (default: undefined).
  • @param children Children.
  • @returns Result.
(property) cx: number
(property) cy: number
(property) r: number

hastscript can also be used as a JSX configuration comment:

/** @jsxImportSource hastscript */

console.log(
  <form method="POST">
    <input type="text" name="foo" />
    <input type="text" name="bar" />
    <input type="submit" name="send" />
  </form>
)
var console: Console
(method) console.Console.log(...data: any[]): void
(property) method: string
(property) type: string
(property) name: string
(property) type: string
(property) name: string
(property) type: string
(property) name: string

xastscript

When working with xast (XML), xastscript can be used.

import {x} from 'xastscript'

console.log(
  x('album', {id: 123}, [
    x('name', 'Exile in Guyville'),
    x('artist', 'Liz Phair'),
    x('releasedate', '1993-06-22')
  ])
)
(alias) function x(): Root (+3 overloads)
(alias) namespace x
import x
var console: Console
(method) console.Console.log(...data: any[]): void
(alias) x(name: string, attributes?: Attributes, ...children: Array<Child>): Element (+3 overloads)
import x
(property) id: number
(alias) x(name: string, ...children: Array<Child>): Element (+3 overloads)
import x
(alias) x(name: string, ...children: Array<Child>): Element (+3 overloads)
import x
(alias) x(name: string, ...children: Array<Child>): Element (+3 overloads)
import x

xastscript can also be used as a JSX configuration comment:

/** @jsxImportSource xastscript */

console.log(
  <album id={123}>
    <name>Born in the U.S.A.</name>
    <artist>Bruce Springsteen</artist>
    <releasedate>1984-04-06</releasedate>
  </album>
)
var console: Console
(method) console.Console.log(...data: any[]): void
(index) IntrinsicElements[string]: any
(property) id: number
(index) IntrinsicElements[string]: any
(index) IntrinsicElements[string]: any
(index) IntrinsicElements[string]: any
(index) IntrinsicElements[string]: any
(index) IntrinsicElements[string]: any
(index) IntrinsicElements[string]: any
(index) IntrinsicElements[string]: any