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.

Extending from another plugin

You can add a new source or a new display from a separate MyST plugin. Your plugin just needs to find the placeholder nodes and fill them in. (To add a built-in source/display to this repo instead, see Contributing.)

How to define your own collector or display function

The {listing} directive emits a listingPlaceholder node carrying the user’s options (source, display, path, sort, limit, ...). Your plugin should ship a document-stage transform that selects those nodes and either:

An item is a plain object; see Items for the fields the built-ins understand.

Staging and ordering

Transforms in MyST can run in one of two stages: document first, and project after. Here are some things to keep in mind to make sure your plugin works properly:

Add a collector

Set node.items for the source you own; leave the rest alone:

const collectStars = {
  name: "listing-collect-stars",
  stage: "document",
  plugin: (_opts, utils) => async (tree) => {
    for (const node of utils.selectAll("listingPlaceholder", tree)) {
      if (node.source !== "stars") continue;        // only the source we own
      node.items = await fetchStars(node.path);      // your async logic here
    }
  },
};

export default { name: "Listing stars", transforms: [collectStars] };

Load both plugins in myst.yml (yours first), and :source: stars now works.

Add a display

Replace a node whose :display: you own with your own AST. By this point a collector has already filled node.items:

const renderBadges = {
  name: "listing-display-badges",
  stage: "document",
  plugin: (_opts, utils) => (tree) => {
    for (const node of utils.selectAll("listingPlaceholder", tree)) {
      if (node.display !== "badges" || node.items === undefined) continue;
      // Replace the placeholder in place with your node.
      const out = { type: "div", children: node.items.map(toBadge) };
      for (const key of Object.keys(node)) if (key !== "type") delete node[key];
      Object.assign(node, out);
    }
  },
};

export default { name: "Listing badges", transforms: [renderBadges] };