@sdoc/markdown-loader
Version:
san markdown loader
101 lines (92 loc) • 3.41 kB
JavaScript
/**
* @file utils
* @author ksky521
*/
const fs = require('fs');
const path = require('path');
const URL = require('url');
const {remove: removeDiacritics} = require('diacritics');
// eslint-disable-next-line no-control-regex
const rControl = /[\u0000-\u001f]/g;
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
exports.slugify = str =>
removeDiacritics(str)
// Remove control characters
.replace(rControl, '')
// Replace special characters
.replace(rSpecial, '-')
// Remove continuous separators
.replace(/\-{2,}/g, '-')
// Remove prefixing and trailing separators
.replace(/^\-+|\-+$/g, '')
// ensure it doesn't start with a number (#121)
.replace(/^(\d)/, '_$1')
// lowercase
.toLowerCase();
const mdLink2Html = str => str.replace(/\.md$/, '/').replace(/README\/$/, '');
exports.mdLink2Html = mdLink2Html;
exports.getRelativeLink = (from, to, rootUrl = '/') => {
to = mdLink2Html(to);
if (path.isAbsolute(to)) {
return rootUrl.replace(/\/+$/, '') + '/' + to.replace(/^\/+/, '');
}
to = URL.resolve(from, to);
if (/^\./.test(to)) {
return to;
}
return rootUrl.replace(/\/+$/, '') + '/' + to.replace(/^\/+/, '');
};
const unescapeHtml = html =>
String(html)
.replace(/"/g, '"')
/* eslint-disable quotes */
.replace(/'/g, "'")
/* eslint-enable quotes */
.replace(/:/g, ':')
.replace(/</g, '<')
.replace(/>/g, '>');
exports.unescapeHtml = unescapeHtml;
const escapeHtml = require('escape-html');
exports.escapeHtml = escapeHtml;
// This method remove the raw HTML but reserve the HTML wrapped by `<code>`.
// e.g.
// Input: "<a> b", Output: "b"
// Input: "`<a>` b", Output: "`<a>` b"
function removeNonCodeWrappedHTML(str) {
return String(str).replace(/(^|[^><`])<.*>([^><`]|$)/g, '$1$2');
}
exports.removeNonCodeWrappedHTML = removeNonCodeWrappedHTML;
const emojiData = require('markdown-it-emoji/lib/data/full.json');
function parseEmojis(str) {
return String(str).replace(/:(.+?):/g, (placeholder, key) => emojiData[key] || placeholder);
}
exports.parseEmojis = parseEmojis;
const removeMarkdownTokens = str =>
String(str)
.replace(/\[(.*)\]\(.*\)/, '$1') // []()
.replace(/(`|\*{1,3}|_)(.*?[^\\])\1/g, '$2') // `{t}` | *{t}* | **{t}** | ***{t}*** | _{t}_
.replace(/(\\)(\*|_|`|\!)/g, '$2');
exports.removeMarkdownTokens = removeMarkdownTokens;
function compose(...processors) {
if (processors.length === 0) {
return input => input;
}
if (processors.length === 1) {
return processors[0];
}
return processors.reduce((prev, next) => {
return (...args) => next(prev(...args));
});
}
exports.compose = compose;
// Unescape html, parse emojis and remove some md tokens.
// eslint-disable-next-line
const parseHeaders = (exports.parseHeaders = v => compose(unescapeHtml, parseEmojis, removeMarkdownTokens, str => str.trim()));
exports.deeplyParseHeaders = compose(removeNonCodeWrappedHTML, parseHeaders)();
function getModulePath(pathname) {
const paths = require.resolve.paths('')
.map(p => path.join(p, pathname))
.filter(p => fs.existsSync(p));
return paths && paths.length > 0 ? paths[0] : '';
};
exports.getModulePath = getModulePath;