markedjs/marked-gfm-heading-id

Wrap headings with sections via existing heading-id plugin

shania-g opened this issue · 2 comments

Hey @UziTech

Just wondering, is there a way to override this plugin to wrap the headings with sections, give the sections the ids, and put an anchor into each heading that points to the section id?

What I imagine is something like this:

Input:

## First section

### Nested first section heading

## Second section

Output:

<section id="first-section">
  <h2>
    <a href="#first-section">First section</a>
  </h2>
  <section id="nested-first-section-heading">
    <h3>
      <a href="#nested-first-section-heading">Nested first section heading</a>
    </h3>
  </section>
</section>

<section id="second-section">
  <h2>
    <a href="#second-section">Second section</a>
  </h2>
</section>

I thought I could use the renderer and only override part of what this extension does, but not sure if this is the right approach and how I would go about it.

marked.use(gfmHeadingId({ prefix: "heading-" }), {
  renderer: {
    // override rendering logic here, but keep existing
  },
  hooks: {
    postprocess(html) {
      const headings = getHeadingList();

      return `
        ${
          headings.length > 0
            ? `<details>
          <summary>Table of contents</summary>
          <ul>
            ${headings
              .map(
                ({ id, raw, level }) => `
                <li><a href="#${id}" class="h${level}">${raw}</a></li>`
              )
              .join("")}
          </ul>
        </details>`
            : ""
        }
        ${html}
      `;
    }
  }
});

You could copy the extension and change the output however you want. After all the whole extension is just 59 lines of code.

Or you can change the renderer on output

import { gfmHeadingId } from "marked-gfm-heading-id";

const gfmExtension = gfmHeadingId(options);

const oldRenderer = gfmExtension.renderer.heading;
gfmExtension.renderer.heading = (token) => {
  const html = oldRenderer(token);
  // do something with output
  return html;
};

marked.use(gfmExtension)