Markdown parser, done right. 100% CommonMark support, extensions, syntax plugins & high speed
https://markdown-it.github.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
157 lines
4.1 KiB
157 lines
4.1 KiB
// Utilities
|
|
//
|
|
'use strict';
|
|
|
|
|
|
function _class(obj) { return Object.prototype.toString.call(obj); }
|
|
|
|
function isString(obj) { return _class(obj) === '[object String]'; }
|
|
|
|
var _hasOwnProperty = Object.prototype.hasOwnProperty;
|
|
|
|
function has(object, key) {
|
|
return object ? _hasOwnProperty.call(object, key) : false;
|
|
}
|
|
|
|
// Merge objects
|
|
//
|
|
function assign(obj /*from1, from2, from3, ...*/) {
|
|
var sources = Array.prototype.slice.call(arguments, 1);
|
|
|
|
sources.forEach(function (source) {
|
|
if (!source) { return; }
|
|
|
|
if (typeof source !== 'object') {
|
|
throw new TypeError(source + 'must be object');
|
|
}
|
|
|
|
Object.keys(source).forEach(function (key) {
|
|
obj[key] = source[key];
|
|
});
|
|
});
|
|
|
|
return obj;
|
|
}
|
|
|
|
// Remove element from array and put another array at those position.
|
|
// Useful for some operations with tokens
|
|
function arrayReplaceAt(src, pos, newElements) {
|
|
return [].concat(src.slice(0, pos), newElements, src.slice(pos + 1));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
var UNESCAPE_MD_RE = /\\([\\!"#$%&'()*+,.\/:;<=>?@[\]^_`{|}~-])/g;
|
|
|
|
function unescapeMd(str) {
|
|
if (str.indexOf('\\') < 0) { return str; }
|
|
return str.replace(UNESCAPE_MD_RE, '$1');
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
function isValidEntityCode(c) {
|
|
/*eslint no-bitwise:0*/
|
|
// broken sequence
|
|
if (c >= 0xD800 && c <= 0xDFFF) { return false; }
|
|
// never used
|
|
if (c >= 0xFDD0 && c <= 0xFDEF) { return false; }
|
|
if ((c & 0xFFFF) === 0xFFFF || (c & 0xFFFF) === 0xFFFE) { return false; }
|
|
// control codes
|
|
if (c >= 0x00 && c <= 0x08) { return false; }
|
|
if (c === 0x0B) { return false; }
|
|
if (c >= 0x0E && c <= 0x1F) { return false; }
|
|
if (c >= 0x7F && c <= 0x9F) { return false; }
|
|
// out of range
|
|
if (c > 0x10FFFF) { return false; }
|
|
return true;
|
|
}
|
|
|
|
function fromCodePoint(c) {
|
|
/*eslint no-bitwise:0*/
|
|
if (c > 0xffff) {
|
|
c -= 0x10000;
|
|
var surrogate1 = 0xd800 + (c >> 10),
|
|
surrogate2 = 0xdc00 + (c & 0x3ff);
|
|
|
|
return String.fromCharCode(surrogate1, surrogate2);
|
|
}
|
|
return String.fromCharCode(c);
|
|
}
|
|
|
|
var NAMED_ENTITY_RE = /&([a-z#][a-z0-9]{1,31});/gi;
|
|
var DIGITAL_ENTITY_TEST_RE = /^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i;
|
|
var entities = require('./entities');
|
|
|
|
function replaceEntityPattern(match, name) {
|
|
var code = 0;
|
|
|
|
if (has(entities, name)) {
|
|
return entities[name];
|
|
} else if (name.charCodeAt(0) === 0x23/* # */ && DIGITAL_ENTITY_TEST_RE.test(name)) {
|
|
code = name[1].toLowerCase() === 'x' ?
|
|
parseInt(name.slice(2), 16)
|
|
:
|
|
parseInt(name.slice(1), 10);
|
|
if (isValidEntityCode(code)) {
|
|
return fromCodePoint(code);
|
|
}
|
|
}
|
|
return match;
|
|
}
|
|
|
|
function replaceEntities(str) {
|
|
if (str.indexOf('&') < 0) { return str; }
|
|
|
|
return str.replace(NAMED_ENTITY_RE, replaceEntityPattern);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
var HTML_ESCAPE_TEST_RE = /[&<>"]/;
|
|
var HTML_ESCAPE_REPLACE_RE = /[&<>"]/g;
|
|
var HTML_REPLACEMENTS = {
|
|
'&': '&',
|
|
'<': '<',
|
|
'>': '>',
|
|
'"': '"'
|
|
};
|
|
|
|
function replaceUnsafeChar(ch) {
|
|
return HTML_REPLACEMENTS[ch];
|
|
}
|
|
|
|
function escapeHtml(str) {
|
|
if (HTML_ESCAPE_TEST_RE.test(str)) {
|
|
return str.replace(HTML_ESCAPE_REPLACE_RE, replaceUnsafeChar);
|
|
}
|
|
return str;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Incoming link can be partially encoded. Convert possible combinations to
|
|
// unified form.
|
|
function normalizeLink(url) {
|
|
var normalized = replaceEntities(url);
|
|
|
|
// We don't care much about result of mailformed URIs,
|
|
// but shoud not throw exception.
|
|
try {
|
|
normalized = decodeURI(normalized);
|
|
} catch (__) {}
|
|
|
|
return encodeURI(normalized);
|
|
}
|
|
|
|
|
|
exports.assign = assign;
|
|
exports.isString = isString;
|
|
exports.has = has;
|
|
exports.unescapeMd = unescapeMd;
|
|
exports.isValidEntityCode = isValidEntityCode;
|
|
exports.fromCodePoint = fromCodePoint;
|
|
exports.replaceEntities = replaceEntities;
|
|
exports.escapeHtml = escapeHtml;
|
|
exports.arrayReplaceAt = arrayReplaceAt;
|
|
exports.normalizeLink = normalizeLink;
|
|
|