Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Contributing

This page is for working on the plugin itself. To build a separate plugin on top of it without editing this repo, see Extending from another plugin.

How the code is laid out

The plugin is a three-stage pipeline, split one file per stage:

{listing}  ->  listingPlaceholder node  ->  collect  ->  transform  ->  render
                                            (sources)   (sort/etc)    (views)

src/plugin.ts also holds the directive and wires the transforms together; src/shared.ts holds a few things they share. The item is the plain object that flows between these stages; see Items for the fields it carries.

Build and test

We use nox to drive the build:

nox -s build      # bundle the plugin to dist/plugin.mjs
nox -s test       # build the docs, then run the vitest suite against the output
nox -s docs-live  # live docs server while you work

The tests build the demo docs and assert on the rendered mdast, so a passing run means the examples on the displays pages actually render.

Cut a release

Two GitHub Actions handle publishing (see .github/workflows/):

To publish a new bundle, draft a release on GitHub with a tag like v0.1.0. The workflow above will automatically add the built .mjs bundle to the release.

Add a built-in display (:display:)

A display takes the items and returns a single AST node. Add a function to the displays map in src/display.ts:

function renderCount(items: any[]) {
  return { type: "paragraph", children: [{ type: "text", value: `${items.length} items` }] };
}

export const displays = { table: renderTable, count: renderCount };

Now :display: count works:

```{listing}
:path: posts/*.md
:display: count
```

Add a built-in collector (:source:)

A collector fills node.items. Add a function to the collectors map in src/collect.ts. For example, a source that reads a JSON array of items:

function collectJson(node: any) {
  node.items = JSON.parse(readFileSync(node.path, "utf-8"));
}

export const collectors = { files: collectFiles, json: collectJson };

Now :source: json :path: data.json works.

Change sorting or filtering

The middle layer lives in src/plugin.ts (applyFilter, sortItems). To add a new behaviour, read a new option off the placeholder and act on the item list before it reaches the display. Return the same shape you receive: a list of items in, a list of items out.

How this package was developed

Here’s a rough timeline for how this package was developed: