Semantic markdown blocks

(updated )

253 words, 2-minute read

Elements such as <aside>, <section>, <article>, and <nav> cannot be expressed in markdown unless you create a block of HTML content. Unfortunately, this means child markdown is not converted. For example:

markdown input

<aside class="a1">
See also:

* [link one](#one)
* [link two](#two)
* [link three](#three)
</aside>

is rendered exactly as shown without any HTML conversion.

The following processContent hook function translates markdown blocks such as ::: aside and ::: /aside to raw HTML:

publican.config.js excerpt

publican.config.processContent.add( data => {

  data.content = data.content
    .replace(/((<.+?>){0,1}\s*:::(.+?)(<\/.+?>){0,1}\n)/gi, (m, p1, p2, p3, p4, pos, str) => {

      // tag offset
      pos += (p2 || '').length + 3;

      if (str.lastIndexOf('<code', pos) > str.lastIndexOf('</code', pos)) {

        // inside a code block - no change
        return p1;

      }
      else {

        // replace ::: tag and smart quotes with HTML
        let tag = `<${
          p3.trim()
            .replace(/[\u2018\u2019]/g, '\'')
            .replace(/[\u201C\u201D]/g, '"')
        }>\n`;

        // swap outer tags
        if (!p2 || !p4) {
          tag = (p4 || '') + tag + (p2 || '');
        }

        return tag;

      }
    });

}

The following markdown:

markdown input

::: aside class="a1"
See also:

* [link one](#one)
* [link two](#two)
* [link three](#three)
::: /aside

now renders:

HTML output

<aside class="a1">
  <p>See also:</p>

  <ul>
    <li><a href="#one">link one</a></li>
    <li><a href="#two">link two</a></li>
    <li><a href="#three">link three</a></li>
  <ul>
</aside>