parent
d8656eac98
commit
1db03e4414
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,28 @@
|
|||||||
|
import test from 'ava';
|
||||||
|
import asciimathToTex from './asciimath-to-tex';
|
||||||
|
|
||||||
|
test('just a number', t => {
|
||||||
|
t.is(asciimathToTex('5'), '{5}');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('x=5', t => {
|
||||||
|
t.is(asciimathToTex('x=5'), '{x}={5}');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('x=5+2', t => {
|
||||||
|
t.is(asciimathToTex('x=5+2'), '{x}={5}+{2}');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('x = (-b+-sqrt(b^2-4ac))/(2a)', t => {
|
||||||
|
t.is(
|
||||||
|
asciimathToTex('x = (-b+-sqrt(b^2-4ac))/(2a)'),
|
||||||
|
'{x}=\\frac{{-{b}\\pm\\sqrt{{{b}^{{2}}-{4}{a}{c}}}}}{{{2}{a}}}',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('{x}=(-b+-sqrt(b^2-4ac))/(2a)', t => {
|
||||||
|
t.is(
|
||||||
|
asciimathToTex('{x}=(-b+-sqrt(b^2-4ac))/(2a)'),
|
||||||
|
'{\\left\\lbrace{x}\\right\\rbrace}=\\frac{{-{b}\\pm\\sqrt{{{b}^{{2}}-{4}{a}{c}}}}}{{{2}{a}}}',
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,121 @@
|
|||||||
|
import katex from 'katex';
|
||||||
|
import renderMathInElement from 'katex/dist/contrib/auto-render';
|
||||||
|
import showdown from 'showdown';
|
||||||
|
import asciimathToTex from './asciimath-to-tex';
|
||||||
|
|
||||||
|
if (process.env.TARGET === 'cjs') {
|
||||||
|
const { JSDOM } = require('jsdom');
|
||||||
|
const jsdom = new JSDOM();
|
||||||
|
global.DOMParser = jsdom.window.DOMParser;
|
||||||
|
global.document = jsdom.window.document;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {object} opts
|
||||||
|
* @param {NodeListOf<Element>} opts.elements
|
||||||
|
* @param opts.config
|
||||||
|
* @param {boolean} opts.isAsciimath
|
||||||
|
*/
|
||||||
|
function renderBlockElements({ elements, config, isAsciimath }) {
|
||||||
|
if (!elements.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.forEach(element => {
|
||||||
|
const input = element.textContent || element.innerText;
|
||||||
|
const latex = isAsciimath ? asciimathToTex(input) : input;
|
||||||
|
const html = katex.renderToString(latex, config);
|
||||||
|
element.parentNode.outerHTML = `<span title="${input.trim()}">${html}</span>`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string} regexp escaped string
|
||||||
|
*/
|
||||||
|
function escapeRegExp(str) {
|
||||||
|
return str.replace(/[-[\]/{}()*+?.\\$^|]/g, '\\$&');
|
||||||
|
}
|
||||||
|
|
||||||
|
// katex config
|
||||||
|
const getConfig = (config = {}) => ({
|
||||||
|
displayMode: true,
|
||||||
|
throwOnError: false, // fail silently
|
||||||
|
errorColor: '#ff0000',
|
||||||
|
...config,
|
||||||
|
delimiters: [
|
||||||
|
{ left: '$$', right: '$$', display: false, asciimath: false },
|
||||||
|
{ left: '~', right: '~', display: false, asciimath: true },
|
||||||
|
].concat(config.delimiters || []),
|
||||||
|
});
|
||||||
|
|
||||||
|
const showdownKatex = userConfig => () => {
|
||||||
|
const parser = new DOMParser();
|
||||||
|
const config = getConfig(userConfig);
|
||||||
|
const asciimathDelimiters = config.delimiters
|
||||||
|
.filter(item => item.asciimath)
|
||||||
|
.map(({ left, right }) => {
|
||||||
|
const l = escapeRegExp(left)
|
||||||
|
const r = escapeRegExp(right)
|
||||||
|
const test = new RegExp(
|
||||||
|
`(?:${l})([^${l}${r}]+)(?:${r})`,
|
||||||
|
'g',
|
||||||
|
);
|
||||||
|
const replacer = (match, asciimath) => {
|
||||||
|
return `${left}${asciimathToTex(asciimath)}${right}`;
|
||||||
|
};
|
||||||
|
return { test, replacer };
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'output',
|
||||||
|
filter(html = '') {
|
||||||
|
const wrapper = parser.parseFromString(html, 'text/html').body;
|
||||||
|
if (asciimathDelimiters.length) {
|
||||||
|
wrapper.querySelectorAll(':not(code):not(pre)').forEach(el => {
|
||||||
|
const textNodes = [...el.childNodes].filter(
|
||||||
|
node => {
|
||||||
|
if (node.nodeName === '#text') {
|
||||||
|
return node.nodeValue.trim()
|
||||||
|
}
|
||||||
|
if (node.nodeName === 'CODE') {
|
||||||
|
return node.innerText.trim()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
textNodes.forEach(node => {
|
||||||
|
const newText = asciimathDelimiters.reduce(
|
||||||
|
(acc, { test, replacer }) => acc.replace(test, replacer),
|
||||||
|
node.nodeValue || node.innerText
|
||||||
|
)
|
||||||
|
if (node.nodeName === '#text') {
|
||||||
|
node.nodeValue = newText
|
||||||
|
} else {
|
||||||
|
node.innerText = newText;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the math in code blocks
|
||||||
|
const latex = wrapper.querySelectorAll('code.latex.language-latex');
|
||||||
|
const asciimath = wrapper.querySelectorAll(
|
||||||
|
'code.asciimath.language-asciimath',
|
||||||
|
);
|
||||||
|
|
||||||
|
renderBlockElements({ elements: latex, config });
|
||||||
|
renderBlockElements({ elements: asciimath, config, isAsciimath: true });
|
||||||
|
renderMathInElement(wrapper, config);
|
||||||
|
|
||||||
|
return wrapper.innerHTML;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
// register extension with default config
|
||||||
|
showdown.extension('showdown-katex', showdownKatex());
|
||||||
|
|
||||||
|
export default showdownKatex;
|
@ -0,0 +1,21 @@
|
|||||||
|
import test from 'ava';
|
||||||
|
import showdown from 'showdown';
|
||||||
|
import katex from '../lib/showdown-katex';
|
||||||
|
|
||||||
|
const input = '# hello, markdown!';
|
||||||
|
const output = '<h1 id="hellomarkdown">hello, markdown!</h1>';
|
||||||
|
|
||||||
|
test('string extension', t => {
|
||||||
|
const converter = new showdown.Converter({
|
||||||
|
extensions: ['showdown-katex'],
|
||||||
|
});
|
||||||
|
t.is(converter.makeHtml(input), output);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('function extension', t => {
|
||||||
|
const converter = new showdown.Converter({
|
||||||
|
extensions: [katex()],
|
||||||
|
});
|
||||||
|
|
||||||
|
t.is(converter.makeHtml(input), output);
|
||||||
|
});
|
Loading…
Reference in new issue