/** * @typedef {import('katex').KatexOptions} KatexOptions * @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension */ /** * @typedef {Omit} Options * Configuration for HTML output. * * > 👉 **Note**: passed to `katex.renderToString`. * > `displayMode` is overwritten by this plugin, to `false` for math in * > text (inline), and `true` for math in flow (block). */ import katex from 'katex' /** @type {import('katex')['default']['renderToString']} */ // @ts-expect-error: types are incorrect. const renderToString = katex.renderToString /** * Create an extension for `micromark` to support math when serializing to * HTML. * * > 👉 **Note**: this uses KaTeX to render math. * * @param {Options | null | undefined} [options={}] * Configuration (default: `{}`). * @returns {HtmlExtension} * Extension for `micromark` that can be passed in `htmlExtensions`, to * support math when serializing to HTML. */ export function mathHtml(options) { return { enter: { mathFlow() { this.lineEndingIfNeeded() this.tag('
') }, mathFlowFenceMeta() { this.buffer() }, mathText() { // Double? this.tag('') this.buffer() } }, exit: { mathFlow() { const value = this.resume() this.tag(math(value.replace(/(?:\r?\n|\r)$/, ''), true)) this.tag('
') this.setData('mathFlowOpen') this.setData('slurpOneLineEnding') }, mathFlowFence() { // After the first fence. if (!this.getData('mathFlowOpen')) { this.setData('mathFlowOpen', true) this.setData('slurpOneLineEnding', true) this.buffer() } }, mathFlowFenceMeta() { this.resume() }, mathFlowValue(token) { this.raw(this.sliceSerialize(token)) }, mathText() { const value = this.resume() this.tag(math(value, false)) this.tag('') }, mathTextData(token) { this.raw(this.sliceSerialize(token)) } } } /** * @param {string} value * Math text. * @param {boolean} displayMode * Whether the math is in display mode. * @returns {string} * HTML. */ function math(value, displayMode) { return renderToString(value, { ...options, displayMode }) } }