mdtocs
Version:
Markdown table of contents generator.
107 lines (98 loc) • 3.43 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.mdtocs = {}));
})(this, (function (exports) { 'use strict';
const CODE_BLOCK_REGEX = /^```.*\n[\s\S]*?```$/gm;
const HEADINGS_REGEX = /^(#{1,6}[ \t].+)$|^(.+[\r\n][=-]{3,})$/gm;
const HEADING_REGEX = /^(#+)[ \t](.+)$|^(.+)[\r\n]([=-])/;
const INVALID_FRAGMENT_REGEX = /[^a-zA-Z0-9_-]/g;
const WHITESPACE_REGEX = /\s/;
const BLANK = '';
const HYPHEN = '-';
const NEWLINE = '\n';
const SPACE = ' ';
const INDENT = SPACE.repeat(2);
const BULLET = HYPHEN + SPACE;
function clean(markdown) {
return markdown.replace(CODE_BLOCK_REGEX, BLANK).trim();
}
function parse(markdown) {
const headings = markdown.match(HEADINGS_REGEX);
if (headings === null) {
return [];
}
const fragments = {};
const initialValue = [];
return headings.reduce((accumulator, heading) => {
const [level, text] = getHeadingLevelAndText(heading);
if (level && text) {
accumulator.push({
level,
text,
fragment: createFragment(text, fragments),
});
}
return accumulator;
}, initialValue);
}
function getHeadingLevelAndText(heading) {
const headingMatch = heading.match(HEADING_REGEX);
if (headingMatch === null) {
return [];
}
const [, headingLevel, headingText, headingTextAlternate, headingLevelAlternate,] = headingMatch;
let text;
let level;
if (headingLevelAlternate) {
level = headingLevelAlternate === HYPHEN ? 2 : 1;
text = headingTextAlternate.trim();
}
else {
level = headingLevel.length;
text = headingText.trim();
}
if (!text) {
return [];
}
return [level, text];
}
function createFragment(text, fragments) {
const fragment = text
.toLowerCase()
.split(WHITESPACE_REGEX)
.join('-')
.replace(INVALID_FRAGMENT_REGEX, '');
const count = fragments[fragment];
if (count) {
fragments[fragment]++;
return fragment + HYPHEN + count;
}
fragments[fragment] = 1;
return fragment;
}
function transform(headings) {
return headings.reduce((accumulator, heading) => {
const { level, text, fragment } = heading;
return (accumulator +
INDENT.repeat(level - 1) +
BULLET +
createLink(text, fragment) +
NEWLINE);
}, '');
}
function createLink(text, fragment) {
return '[' + text + '](#' + fragment + ')';
}
function validate(markdown) {
if (typeof markdown !== 'string') {
throw new TypeError('First argument must be a string');
}
return markdown;
}
function mdtocs(markdown) {
return transform(parse(clean(validate(markdown))));
}
exports.mdtocs = mdtocs;
}));
//# sourceMappingURL=mdtocs.js.map