npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

remark-code-figure

v0.2.2

Published

A remark plugin that wraps code blocks with a figure and adds an optional figcaption.

Downloads

2

Readme

remark-code-figure

A remark plugin that wraps code blocks in figure elements with an optional figcaption.

Installation

npm install remark-code-figure

Usage

remark-code-figure can be used with remark or with unifiedjs.

We have the following test.md file.

# Example markdown

```js My caption text
console.log("Hello, world!");
```

Let's look at a few ways this can be processed with tools in the unified collective.

To Markdown

You can process markdown input and return the transformed markdown output (the figure element will be written directly into markdown):

import report from 'vfile-reporter'; // for reporting errors
import {readSync, writeSync} from 'to-vfile'; // for reading our markdown file
import { remark } from 'remark';
import remarkStringify from 'remark-stringify';
import codeCaption from 'remark-code-caption';

// our processing function
async function mdToRemark(buffer) {
  return await remark()
    .use(codeFigure)
    .use(remarkStringify)
    .process(readSync('./test.md'))
    .then(async (file) => {
      console.error(report(file));
      writeSync({path: './marked-test.md', value: String(await file)});
    })
}

mdToRemark();

This will write marked-test.md to the file system for us. That file will look like:

# Example markdown

<figure class="code-figure">
  <pre>
    <code class="language-js">
      console.log("Hello, world!");
    </code>
  </pre>
  <figcaption class="code-caption">
    My caption text
  </figcaption>
</figure>

To HTML

You can also process markdown input into partial html output. Make sure to use {sanitize: false} in the remarkHtml options or the figure element and its children will be stripped from the document. After that, though, you'll want to use rehype-sanitize to protect yourself from xss attacks.

async function mdHTML() {
  return await unified() // you can also use remark!
    .use(remarkParse) // but leave this line out if you do
    .use(codeFigure)
    .use(remarkHtml, {sanitize: false}) // important!
    .use(rehypeSanitize)
    .process(readSync('./test.md'))
    .then(async (file) => {
      console.error(report(file));
      writeSync({path: './html-test.html', value: String(await file)});
    });
}

mdHTML();

Which will give you:

<h1>Test Markdown file</h1>
<figure class="code-figure">
  <pre>
    <code class="language-js">
      console.log("Hello, world");
    </code>
  </pre>
  <figcaption class=code-caption>
    My caption text
  </figcaption>
</figure>

Syntax Highlighting

At the moment, this plugin will work with remark-shiki, but will not work with remark-prism.

This plugin will work with @mapbox/rehype-prism though, you'll just need to call things in the correct order, it's also recommended to use rehype-sanitize to help ensure your final output is safe from XSS attacks:

import prism from '@mapbox/rehype-prism';

async function mdPrism() {
  return await remark()
    .use(remarkRehype, {allowDangerousHtml: true})
    .use(prism)
    .use(codeFigure)
    .use(rehypeRaw)
    .use(rehypeSanitize)
    .use(rehypeDocument)
    .use(rehypeFormat) // make your html output look nice!
    .use(rehypeStringify)
    .process(readSync('./test.md'))
    .then(async (file) => {
      console.error(report(file));
      writeSync({path: './mdPrism.html', value: String(await file)});
    })
    
  }

mdPrism();

If you want to highlight with remark-shiki, you need to install shiki as a separate dependency.

You'll also need to call the shiki.getHighlighter function:

async function mdShiki() {
  const highlighter = await shiki.getHighlighter({theme: 'nord'});

  return remark()
    .use(remarkShiki, {highlighter})
    .use(codeFigure)
    .use(remarkRehype, {allowDangerousHtml: true})
    .use(rehypeRaw)
    .use(rehypeSanitize)
    .use(rehypeDocument)
    .use(rehypeFormat)
    .use(rehypeStringify)
    .process(readSync('./test.md'))
    .then(async(file) => {
      console.error(report(file));
      writeSync({path: './mdShiki.html', value: String(await file)});
    });
}

mdShiki();

Options

Options are passed to codeFigure as an object. By default, that object looks like this:

{
 className: 'code-figure', 
 captionOptions: {
   disable: false, 
   position: 'after', 
   className: 'code-caption'
 }
}

options.className

Specifies the class name of the figure element. Defaults to code-figure.

{
  type: string,
  default: 'code-figure'
}

options.captionOptions.disable

Specifies whether to disable the figcaption element.

{
  type: boolean,
  default: false
}

options.captionOptions.position

Specifies the position of the figcaption element. Can be either "before" or "after".

{
  type: string,
  default: 'after'
}

options.captionOptions.className

Specifies the class name for the figcaption element. Defaults to code-caption.

{
  type: string,
  default: 'code-caption'
}