Skip to content

mdast extension to parse and serialize gridtables

License

Notifications You must be signed in to change notification settings

adobe/mdast-util-gridtables

MDAST Util Gridtables

Mdast utility that serializes gridtables to mdast and/or hast.

Status

codecov GitHub Actions Workflow Status GitHub license GitHub issues semantic-release

What is this?

This package contains extensions that add support for the grid table syntax to mdast-util-from-markdown and mdast-util-to-markdown.

When to use this

These tools are all rather low-level. In most cases, you’d want to use [@adobe/remark-gridtables][remark-gridtables] with remark instead.

When working with mdast-util-from-markdown, you must combine this package with @adobe/micromark-extension-gridtables.

This utility does not handle how markdown is turned to HTML. That’s done by mdast-util-to-hast.

Install

This package is ESM only. In Node.js (version 12.20+, 14.14+, or 16.0+), install with npm:

npm install @adobe/mdast-util-gridtables

Usage

Note: due to the architecture of the micromark parser, it is not possible to parse the cell contents continuously. Furthermore, the to-markdown utility doesn't make its configuration available to extensions, so we need to pass the configuration manually into the gridtables extension.

import fs from 'node:fs/promises';
import { fromMarkdown } from 'mdast-util-from-markdown';
import { toMarkdown } from 'mdast-util-to-markdown';
import { gridTables } from '@adobe/micromark-extension-gridtables'
import { 
  gridTablesToMarkdown, 
  gridTablesFromMarkdown, 
  mdast2hastGridTablesHandler,
  TYPE_TABLE,
} from '@adobe/mdast-util-gridtables';

const doc = await fs.readFile('example.md')

// convert markdown to mdast
const options = {
  extensions: [gridTables],
  mdastExtensions: [],
};
options.mdastExtensions.push(gridTablesFromMarkdown(options));
const tree = fromMarkdown(sourceMarkdown, options);

// convert mdast to md
const outputMarkdown = toMarkdown(tree, {extensions: [gridTablesToMarkdown()]})

// convert mdast to hast
const hast = mdast2hast(mdast, {
  handlers: {
    [TYPE_TABLE]: mdast2hastGridTablesHandler(),
  },
});

Also see a working example.

Overview

GridTables look like this:

+-------------------+------+
| Table Headings    | Here |
+--------+----------+------+
| Sub    | Headings | Too  |
+========+=================+
| cell   | column spanning |
| spans  +---------:+------+
| rows   |   normal | cell |
+---v----+:---------------:+
|        | cells can be    |
|        | *formatted*     |
|        | **paragraphs**  |
|        | ```             |
| multi  | and contain     |
| line   | blocks          |
| cells  | ```             |
+========+=========<+======+
| footer |    cells |      |
+--------+----------+------+
  • the top of a cell must be indicated by +- followed by some - or + and finished by -+.
  • if the table contains a footer but no header, the top row should use = as grid line.
  • col spans are indicated by missing column (|) delimiters
  • row spans are indicated by missing row (-) delimiters
  • cells can be left, center, right, or justify aligned; indicated by the placement of : or ><
  • cells can be top, middle, or bottom v-aligned; indicated by the placement of arrows (v ^ x)
  • the header and footer sections are delimited by section delimiters (=).
  • if no section delimiters are present, all cells are placed in the table body.
  • if only 1 section delimiter is present, it delimits header from body.
  • the content in cells can be a full Markdown document again. note, that the cell boundaries (|) need to exactly match with the column markers (+) in the row delimiters, if the cell content contains |, otherwise the correct layout of the table can't be guaranteed.

Layout

The table layout tries to keep the table within a certain width (default 120). For example, if the table has 3 columns, each column will be max 40 characters wide. If all text in a column is smaller, it will shrink the columns. However, cells have a minimum width (default 10) when text needs to be broken. If the cell contents need more space, e.g. with a nested table or code block, it will grow accordingly.

Align

Horizontal align is indicated by placing markers at the grid line above the cell:

Justify     Center     Left       Right
+>-----<+  +:-----:+  +:------+  +------:+
| A b C |  |  ABC  |  | ABC   |  |   ABC |
+-------+  +-------+  +-------+  +-------+

Vertical align is indicated by placing markers at the center of the grid line above the cell:

Top        Middle     Bottom
+---^---+  +---x---+  +---v---+
| Larum |  |       |  |       |
| Ipsum |  | Larum |  |       |
|       |  | Ipsum |  | Larum |
|       |  |       |  | Ipsum |
+-------+  +-------+  +-------+

Syntax


gridTable := gridLine cellLine+ gridLine;
gridLine := gridCell+ "+";
cellLine := ( gridCell | cellContent )+ ( "+" | "|" );   
gridCell := "+" alignMarkerStart? ("-" | "=")+ vAlignMarker? ("-" | "=")* alignMarkerEnd?;
cellContent := ( "+" | "|" ) " " content " " ;
alignMarkerStart := ":" | ">";
alignMarkerEnd   := ":" | "<";
vAlignMarker     := "^" | "v" | "x"

MDAST Syntax tree

The following interfaces are added to mdast by this utility.

Nodes

GridTable

interface GridTable <: Parent {
  type: "gridTable"
  children: [GridTableHeader|GridTableBody|GridTableFooter]
}

GridTableHeader

interface GridTableHeader <: Parent {
  type: "gtHead"
  children: [GridTableRow]
}

GridTableBody

interface GridTableBody <: Parent {
  type: "gtBody"
  children: [GridTableRow]
}

GridTableFoot

interface GridTableFooter <: Parent {
  type: "gtFoot"
  children: [GridTableRow]
}

GridTableRow

interface GridTableRow <: Parent {
  type: "gtRow"
  children: [GridTableCell]
}

GridTableCell

interface GridTableCell <: Parent {
  type: "gtCell"
  colSpan: number >= 1
  rowSpan: number >= 1
  align: alignType
  valign: valignType
  children: [MdastContent]
}

GridTableCell (Parent) represents a header cell in a GridTable, if its parent is a [gridTableHead][term-head], or a data cell otherwise.

GridTableCell can be used where gridTableRow content is expected. Its content model is mdast content, allowing full mdast documents.

Enumeration

alignType

enum alignType {
  "left" | "right" | "center" | "justify" | null
}

valignType

enum alignType {
  "top" | "bottom" | "middle" | null
}