@digitalocean/do-markdownit
Version:
Markdown-It plugin for the DigitalOcean Community.
86 lines (70 loc) • 2.9 kB
JavaScript
/*
Copyright 2022 DigitalOcean
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
;
/**
* @module modifiers/fence_environment
*/
const safeObject = require('../util/safe_object');
/**
* @typedef {Object} FenceEnvironmentOptions
* @property {string[]} [allowedEnvironments] List of case-sensitive environments that are allowed. If not an array, all environments are allowed.
* @property {string} [extraClasses=''] String of extra classes to set when an environment is used.
*/
/**
* Add support for environment markup at the start of a fence, translating to a class.
*
* Markup must be at the start of the fence, though may be preceded by other metadata markup using square brackets.
*
* @example
* ```
* [environment test]
* hello
* world
* ```
*
* <pre><code class="environment-test">hello
* world
* </code></pre>
*
* @type {import('markdown-it').PluginWithOptions<FenceEnvironmentOptions>}
*/
module.exports = (md, options) => {
// Get the correct options
const optsObj = safeObject(options);
/**
* Wrap the fence render function to detect environment markup and replace it with the correct class.
*
* @param {import('markdown-it/lib/renderer').RenderRule} original The original render function to wrap.
* @returns {import('markdown-it/lib/renderer').RenderRule}
* @private
*/
const render = original => (tokens, idx, opts, env, self) => {
// Get the token
const token = tokens[idx];
// Look for an environment at the start of the content
const match = token.content.match(/^((?:\[.+\]\n)*?)\[environment (.+)\]\n/);
const name = (match && (match[2] || '').trim()) || null;
// If no environment, or not allowed, return the original
if (!name || (optsObj.allowedEnvironments && !optsObj.allowedEnvironments.includes(name))) {
return original(tokens, idx, opts, env, self);
}
// Remove the environment line from the content
token.content = token.content.replace(match[0], match[1]);
// Add the environment to the classes
const classes = optsObj.extraClasses ? `${optsObj.extraClasses} environment-${name}` : `environment-${name}`;
token.attrJoin('class', classes);
// Render
return original(tokens, idx, opts, env, self);
};
md.renderer.rules.fence = render(md.renderer.rules.fence);
};