mathpix-markdown-it
Version:
Mathpix-markdown-it is an open source implementation of the mathpix-markdown spec written in Typescript. It relies on the following open source libraries: MathJax v3 (to render math with SVGs), markdown-it (for standard Markdown parsing)
368 lines • 12.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.renderRuleImage = exports.imageWithSize = exports.parseImageParams = void 0;
var isSpace = require('markdown-it/lib/common/utils').isSpace;
var normalizeReference = require('markdown-it/lib/common/utils').normalizeReference;
var parze_link_destination_1 = require("../../helpers/parze_link_destination");
var percentageRegex = /([\d.]+)%/i;
var sizeRegex = /([\d.]+)(px|pt|em|cm|mm|in)/i;
var getSizeValue = function (strVal, latexLength) {
if (latexLength === void 0) { latexLength = '\\textwidth'; }
var latex = '';
var val = '';
var match = strVal.match(percentageRegex);
if (match) {
latex = (Number(match[1]) / 100).toString() + latexLength;
val = match[0];
}
else {
match = strVal.match(sizeRegex);
if (match) {
latex = match[0];
val = match[0];
}
}
return {
latex: latex,
val: val
};
};
var parseImageParams = function (str, align) {
if (align === void 0) { align = ''; }
if (!str) {
return null;
}
var params = [];
var style = '';
var latex = '';
var res = [];
var size = null;
str = str.replace(/ /g, '');
if (str) {
params = str.split(',');
}
for (var i = 0; i < params.length; i++) {
var param = params[i].split('=');
if (['left', 'right', 'center'].indexOf(param[0]) >= 0) {
align = param[0];
}
var val = param[1]
? param[1].replace(/"/g, '').replace(/'/g, '')
: '';
val = val ? val.trim() : '';
if (!val) {
continue;
}
switch (param[0]) {
case 'width':
size = getSizeValue(val, '\\textwidth');
if (size === null || size === void 0 ? void 0 : size.val) {
style += "".concat(param[0], ": ").concat(val, ";");
res.push(['width', val]);
}
if (size === null || size === void 0 ? void 0 : size.latex) {
latex += latex ? ', ' : '';
latex += 'width=';
latex += size.latex;
}
break;
case 'height':
size = getSizeValue(val, '\\textheight');
if (size === null || size === void 0 ? void 0 : size.val) {
style += "".concat(param[0], ": ").concat(val, ";");
res.push(['height', val]);
}
if (size === null || size === void 0 ? void 0 : size.latex) {
latex += latex ? ', ' : '';
latex += 'height=';
latex += size.latex;
}
break;
case 'align':
align = val;
break;
default:
break;
}
}
if (align) {
res.push(['data-align', align]);
}
res.push(['style', style]);
return style || res
? { attr: res, align: align, latex: latex }
: null;
};
exports.parseImageParams = parseImageParams;
/** Process 
* Replace image inline rule:
* Process:
* 
* {width=50%}
* {width="10px"}
* {width="20px",height="20px"}
* {width="20px",height="20px",right}
* */
var imageWithSize = function (state, silent) {
var _a, _b;
var attrs, code, content, label, labelEnd, labelStart, pos, ref, res, title, token, start, href = '', oldPos = state.pos, max = state.posMax;
var pathOrigin = '';
var attrsStyles = [];
var params = null;
var meta = {};
if (state.src.charCodeAt(state.pos) !== 0x21 /* ! */) {
return false;
}
if (state.src.charCodeAt(state.pos + 1) !== 0x5B /* [ */) {
return false;
}
labelStart = state.pos + 2;
labelEnd = state.md.helpers.parseLinkLabel(state, state.pos + 1, false);
// parser failed to find ']', so it's not a valid link
if (labelEnd < 0) {
return false;
}
pos = labelEnd + 1;
if (pos < max && state.src.charCodeAt(pos) === 0x28 /* ( */) {
//
// Inline link
//
// [link]( <href> "title" )
// ^^ skipping these spaces
pos++;
for (; pos < max; pos++) {
code = state.src.charCodeAt(pos);
if (!isSpace(code) && code !== 0x0A) {
break;
}
}
if (pos >= max) {
return false;
}
// [link]( <href> "title" )
// ^^^^^^ parsing link destination
start = pos;
if ((_a = state.md.options) === null || _a === void 0 ? void 0 : _a.enableFileLinks) {
res = (0, parze_link_destination_1.parseLinkDestination)(state.src, pos, state.posMax);
}
else {
res = state.md.helpers.parseLinkDestination(state.src, pos, state.posMax);
}
if (res.ok) {
href = state.md.normalizeLink(res.str);
pathOrigin = res.str;
if (state.md.validateLink(href)) {
pos = res.pos;
}
else {
href = '';
}
}
// [link]( <href> "title" )
// ^^ skipping these spaces
start = pos;
for (; pos < max; pos++) {
code = state.src.charCodeAt(pos);
if (!isSpace(code) && code !== 0x0A /* \n */) {
break;
}
}
// [link]( <href> "title" )
// ^^^^^^^ parsing link title
res = state.md.helpers.parseLinkTitle(state.src, pos, state.posMax);
if (pos < max && start !== pos && res.ok) {
title = res.str;
pos = res.pos;
// [link]( <href> "title" )
// ^^ skipping these spaces
for (; pos < max; pos++) {
code = state.src.charCodeAt(pos);
if (!isSpace(code) && code !== 0x0A) {
break;
}
}
}
else {
title = '';
}
if (pos >= max || state.src.charCodeAt(pos) !== 0x29 /* ) */) {
state.pos = oldPos;
return false;
}
pos++;
/** customize image width, height, align */
var oldPosParam = pos;
var strParams = '';
var hasCloseBranch = false;
// [link]( <href> "title" ) {width=50%}
// ^^ skipping these spaces
for (; pos < max; pos++) {
code = state.src.charCodeAt(pos);
if (!isSpace(code) && code !== 0x0A) {
break;
}
}
if (pos >= max || state.src.charCodeAt(pos) !== 123 /* { */) {
state.pos = oldPosParam;
}
else {
oldPosParam = pos;
if (state.src.charCodeAt(pos) === 123 /* { */) {
for (; pos < max; pos++) {
code = state.src.charCodeAt(pos);
if (oldPosParam < pos && state.src.charCodeAt(pos) === 123 /* { */) {
strParams = '';
break;
}
strParams += state.src[pos];
if (code === 125 /* } */) {
pos++;
hasCloseBranch = true;
break;
}
}
}
}
// parser params failed to find '}', so it's not a valid params
if (!hasCloseBranch) {
pos = oldPosParam;
}
else {
if (strParams === null || strParams === void 0 ? void 0 : strParams.trim()) {
meta = {
paramsContent: strParams
};
strParams = strParams
.replace('{', '')
.replace('}', '');
strParams = strParams ? strParams.trim() : '';
if (state.md.options.centerImages) {
params = (0, exports.parseImageParams)(strParams, 'center');
}
else {
params = (0, exports.parseImageParams)(strParams, '');
}
if (params) {
attrsStyles = attrsStyles.concat(params.attr);
}
}
}
}
else {
//
// Link reference
//
if (typeof state.env.references === 'undefined') {
return false;
}
if (pos < max && state.src.charCodeAt(pos) === 0x5B /* [ */) {
start = pos + 1;
pos = state.md.helpers.parseLinkLabel(state, pos);
if (pos >= 0) {
label = state.src.slice(start, pos++);
}
else {
pos = labelEnd + 1;
}
}
else {
pos = labelEnd + 1;
}
// covers label === '' and label === undefined
// (collapsed reference link and shortcut reference link respectively)
if (!label) {
label = state.src.slice(labelStart, labelEnd);
}
ref = state.env.references[normalizeReference(label)];
if (!ref) {
state.pos = oldPos;
return false;
}
href = ref.href;
title = ref.title;
}
//
// We found the end of the link, and know for a fact it's a valid link;
// so all that's left to do is to call tokenizer.
//
if (!silent) {
content = state.src.slice(labelStart, labelEnd) || '';
token = state.push('image', 'img', 0);
attrs = [['src', href], ['alt', content]];
if (((_b = state.md.options) === null || _b === void 0 ? void 0 : _b.enableFileLinks) && pathOrigin) {
attrs.push(['data-origin-src', pathOrigin]);
}
if (attrsStyles === null || attrsStyles === void 0 ? void 0 : attrsStyles.length) {
attrs = attrs.concat(attrsStyles);
}
else {
if (state.md.options.centerImages) {
attrs = attrs.concat([['data-align', 'center']]);
}
}
token.attrs = attrs;
token.children = [];
token.content = content;
token.inlinePos = {
start: 0,
end: pos
};
token.meta = meta;
if (params === null || params === void 0 ? void 0 : params.latex) {
token.latex = params.latex;
}
if (title) {
attrs.push(['title', title]);
}
}
state.pos = pos;
state.posMax = max;
return true;
};
exports.imageWithSize = imageWithSize;
var renderRuleImage = function (tokens, idx, options, env, slf) {
var token = tokens[idx];
var tokenBeforeType = idx - 1 >= 0 ? tokens[idx - 1].type : '';
var tokenAfterType = idx + 1 < tokens.length ? tokens[idx + 1].type : '';
// "alt" attr MUST be set, even if empty. Because it's mandatory and
// should be placed on proper position for tests.
//
// Replace content with actual value
var altIndex = token.attrIndex('alt');
var content = token.content || '';
if (altIndex < 0) {
token.attrs.push(['alt', content]);
}
else {
if (!token.attrs[altIndex][1]) {
token.attrs[altIndex][1] = content;
}
}
var canBeBlock = tokens.length === 1
|| (tokenBeforeType === 'softbreak' && !tokenAfterType)
|| (tokenAfterType === 'softbreak' && !tokenBeforeType)
|| (tokenBeforeType === 'softbreak' && tokenAfterType === 'softbreak');
var align = token.attrGet('data-align');
if (canBeBlock) {
if (!align && options.centerImages) {
align = 'center';
token.attrSet('data-align', align);
}
var res = align
? "<figure style=\"text-align: ".concat(align, "\">")
: '<figure>';
res += slf.renderToken(tokens, idx, options);
res += res = '</figure>';
return res;
}
else {
/** Remove data-align attribute from inline image */
if (align) {
var index = token.attrIndex('data-align');
token.attrs.splice(index, 1);
}
}
return slf.renderToken(tokens, idx, options);
};
exports.renderRuleImage = renderRuleImage;
//# sourceMappingURL=image.js.map