markedjs / marked-gfm-heading-id

Add unique heading ids like GitHub
https://www.npmjs.com/package/marked-gfm-heading-id
MIT License
16 stars 7 forks source link

Wrap headings with sections via existing heading-id plugin #580

Open shania-g opened 3 weeks ago

shania-g commented 3 weeks ago

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}
      `;
    }
  }
});
UziTech commented 3 weeks ago

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

UziTech commented 3 weeks ago

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)