diff --git a/packages/rehype-mathjax/browser.js b/packages/rehype-mathjax/browser.js index a1bd647..246d075 100644 --- a/packages/rehype-mathjax/browser.js +++ b/packages/rehype-mathjax/browser.js @@ -2,39 +2,23 @@ * @typedef {import('hast').Root} Root * @typedef {import('hast').Element} Element * @typedef {import('./lib/create-plugin').MathNotation} MathNotation - * @typedef {import('./lib/create-plugin').BrowserOptions} Options + * @typedef {import('./lib/create-plugin').Options} Options */ import {createPlugin} from './lib/create-plugin.js' -const rehypeMathJaxBrowser = - /** @type {import('unified').Plugin<[Options?]|void[], Root>} */ ( - createPlugin( - // To do next major: Make `options` match the format of MathJax options - // `{tex: ...}` - (_, options) => { - /** @type {MathNotation} */ - let display = ['\\[', '\\]'] - /** @type {MathNotation} */ - let inline = ['\\(', '\\)'] +const rehypeMathJaxBrowser = createPlugin((options) => { + const tex = options.tex || {} + const display = tex.displayMath || [['\\[', '\\]']] + const inline = tex.inlineMath || [['\\(', '\\)']] - if ('displayMath' in options && options.displayMath) { - display = options.displayMath - } - - if ('inlineMath' in options && options.inlineMath) { - inline = options.inlineMath - } - - return { - render(node, options) { - const delimiters = options.display ? display : inline - node.children.unshift({type: 'text', value: delimiters[0]}) - node.children.push({type: 'text', value: delimiters[1]}) - } - } - } - ) - ) + return { + render(node, options) { + const delimiters = (options.display ? display : inline)[0] + node.children.unshift({type: 'text', value: delimiters[0]}) + node.children.push({type: 'text', value: delimiters[1]}) + } + } +}) export default rehypeMathJaxBrowser diff --git a/packages/rehype-mathjax/chtml.js b/packages/rehype-mathjax/chtml.js index 2ccff67..90e3397 100644 --- a/packages/rehype-mathjax/chtml.js +++ b/packages/rehype-mathjax/chtml.js @@ -1,20 +1,21 @@ /** * @typedef {import('hast').Root} Root - * @typedef {import('./lib/create-plugin').CHtmlOptions} Options + * @typedef {import('mathjax-full/js/output/chtml.js').CHTML} CHTML_ + * @typedef {import('./lib/create-plugin').Options} Options */ -import {createOutputChtml} from './lib/create-output-chtml.js' +import {CHTML} from 'mathjax-full/js/output/chtml.js' import {createRenderer} from './lib/create-renderer.js' import {createPlugin} from './lib/create-plugin.js' -const rehypeMathJaxCHtml = - /** @type {import('unified').Plugin<[Options?]|void[], Root>} */ - ( - createPlugin( - (inputOptions, outputOptions) => - createRenderer(inputOptions, createOutputChtml(outputOptions)), - true +const rehypeMathJaxCHtml = createPlugin((options) => { + if (!options.chtml || !options.chtml.fontURL) { + throw new Error( + 'rehype-mathjax: missing `fontURL` in options, which must be set to a URL to reach MathJaX fonts' ) - ) + } + + return createRenderer(options, new CHTML(options.chtml)) +}) export default rehypeMathJaxCHtml diff --git a/packages/rehype-mathjax/lib/create-input.js b/packages/rehype-mathjax/lib/create-input.js deleted file mode 100644 index 30b3d00..0000000 --- a/packages/rehype-mathjax/lib/create-input.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * @typedef {import('mathjax-full/js/util/Options.js').OptionList} OptionList - * @typedef {import('mathjax-full/js/input/tex.js').TeX} TeX_ - */ - -import {TeX} from 'mathjax-full/js/input/tex.js' -import {AllPackages} from 'mathjax-full/js/input/tex/AllPackages.js' - -/** - * @param {OptionList} options - * @returns {TeX_} - */ -export function createInput(options) { - return new TeX(Object.assign({packages: AllPackages}, options)) -} diff --git a/packages/rehype-mathjax/lib/create-output-chtml.js b/packages/rehype-mathjax/lib/create-output-chtml.js deleted file mode 100644 index cb6fdd9..0000000 --- a/packages/rehype-mathjax/lib/create-output-chtml.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @typedef {import('mathjax-full/js/util/Options.js').OptionList} OptionList - * @typedef {import('mathjax-full/js/output/chtml.js').CHTML} CHTML_ - */ - -import {CHTML} from 'mathjax-full/js/output/chtml.js' - -/** - * @param {OptionList} options - * @returns {CHTML_} - */ -export function createOutputChtml(options) { - return new CHTML(options) -} diff --git a/packages/rehype-mathjax/lib/create-output-svg.js b/packages/rehype-mathjax/lib/create-output-svg.js deleted file mode 100644 index c2763f4..0000000 --- a/packages/rehype-mathjax/lib/create-output-svg.js +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @typedef {import('mathjax-full/js/util/Options.js').OptionList} OptionList - * @typedef {import('mathjax-full/js/output/svg.js').SVG} SVG_ - */ - -import {SVG} from 'mathjax-full/js/output/svg.js' - -/** - * @param {OptionList} options - * @returns {SVG_} - */ -export function createOutputSvg(options) { - return new SVG(options) -} diff --git a/packages/rehype-mathjax/lib/create-plugin.js b/packages/rehype-mathjax/lib/create-plugin.js index e7ee18d..97a6569 100644 --- a/packages/rehype-mathjax/lib/create-plugin.js +++ b/packages/rehype-mathjax/lib/create-plugin.js @@ -6,14 +6,7 @@ * Markers to use for math. * See: * - * @typedef BrowserOptions - * Configuration. - * @property {MathNotation} [displayMath] - * Markers to use for blocks. - * @property {MathNotation} [inlineMath] - * Markers to use for inlines. - * - * @typedef MathJaxSvgOptions + * @typedef OutputSvgOptions * * @property {number} [scale] * @property {number} [minScale] @@ -29,7 +22,7 @@ * @property {boolean} [internalSpeechTitles] * @property {number} [titleID] * - * @typedef MathJaxCHtmlOptions + * @typedef OutputCHtmlOptions * * @property {number} [scale] * @property {number} [minScale] @@ -44,7 +37,7 @@ * @property {string} fontURL * @property {boolean} [adaptiveCSS] * - * @typedef MathJaxInputTexOptions + * @typedef InputTexOptions * * @property {string[]} [packages] * @property {MathNotation[]} [inlineMath] @@ -63,47 +56,37 @@ * @property {string} [baseURL] * @property {(jax: any, error: any) => string} [formatError] * - * @typedef {MathJaxCHtmlOptions & {tex?: MathJaxInputTexOptions}} CHtmlOptions - * @typedef {MathJaxSvgOptions & {tex?: MathJaxInputTexOptions}} SvgOptions - * - * @typedef {BrowserOptions|CHtmlOptions|SvgOptions} Options + * @typedef Options + * Configuration. + * @property {InputTexOptions} [tex] + * Configuration for the input TeX. + * @property {OutputCHtmlOptions} [chtml] + * Configuration for the output (when CHTML). + * @property {OutputSvgOptions} [svg] + * Configuration for the output (when SVG). * * @typedef Renderer * @property {(node: Element, options: {display: boolean}) => void} render * @property {() => Element} [styleSheet] * * @callback CreateRenderer - * @param {MathJaxInputTexOptions} inputOptions - * @param {MathJaxCHtmlOptions|MathJaxSvgOptions|BrowserOptions} outputOptions + * @param {Options} options * @returns {Renderer} */ import {visit, SKIP} from 'unist-util-visit' -// To do next major: Remove `chtml` and `browser` flags once all the options use -// the same format. - /** * @param {CreateRenderer} createRenderer - * @param {boolean} [chtml=false] */ -export function createPlugin(createRenderer, chtml) { +export function createPlugin(createRenderer) { /** @type {import('unified').Plugin<[Options?]|void[], Root>} */ return (options = {}) => { - if (chtml && (!('fontURL' in options) || !options.fontURL)) { - throw new Error( - 'rehype-mathjax: missing `fontURL` in options, which must be set to a URL to reach MathJaX fonts' - ) - } - - // @ts-expect-error: hush. - const {tex, ...outputOptions} = options - return (tree) => { - const renderer = createRenderer(tex || {}, outputOptions) + const renderer = createRenderer(options) + let found = false /** @type {Root|Element} */ let context = tree - let found = false visit(tree, 'element', (node) => { const classes = diff --git a/packages/rehype-mathjax/lib/create-renderer.js b/packages/rehype-mathjax/lib/create-renderer.js index b953444..cd97255 100644 --- a/packages/rehype-mathjax/lib/create-renderer.js +++ b/packages/rehype-mathjax/lib/create-renderer.js @@ -2,14 +2,17 @@ * @typedef {import('hast').Element} Element * @typedef {import('mathjax-full/js/core/OutputJax').OutputJax} OutputJax * @typedef {import('mathjax-full/js/core/MathDocument.js').MathDocument} MathDocument - * @typedef {import('./create-plugin.js').CreateRenderer} CreateRenderer + * @typedef {import('mathjax-full/js/input/tex.js').TeX} TeX_ + * @typedef {import('./create-plugin.js').Options} Options + * @typedef {import('./create-plugin.js').Renderer} Renderer */ import {mathjax} from 'mathjax-full/js/mathjax.js' import {RegisterHTMLHandler} from 'mathjax-full/js/handlers/html.js' +import {TeX} from 'mathjax-full/js/input/tex.js' +import {AllPackages} from 'mathjax-full/js/input/tex/AllPackages.js' import {fromDom} from 'hast-util-from-dom' import {toText} from 'hast-util-to-text' -import {createInput} from './create-input.js' import {createAdaptor} from './create-adaptor.js' const adaptor = createAdaptor() @@ -28,11 +31,12 @@ const adaptor = createAdaptor() RegisterHTMLHandler(adaptor) /** - * @type {CreateRenderer} + * @param {Options} options * @param {OutputJax} output + * @returns {Renderer} */ -export function createRenderer(inputOptions, output) { - const input = createInput(inputOptions) +export function createRenderer(options, output) { + const input = new TeX(Object.assign({packages: AllPackages}, options.tex)) /** @type {MathDocument} */ const doc = mathjax.document('', {InputJax: input, OutputJax: output}) diff --git a/packages/rehype-mathjax/readme.md b/packages/rehype-mathjax/readme.md index 754b83d..f3fc00b 100644 --- a/packages/rehype-mathjax/readme.md +++ b/packages/rehype-mathjax/readme.md @@ -123,11 +123,22 @@ Options are not passed to MathJax: do that yourself on the client. All options, except when using the browser plugin, are passed to [MathJax][mathjax-options]. -Specifically, they are passed to the chosen output processor. #### `options.tex` These options are passed to the [TeX input processor][mathjax-tex-options]. +The browser plugin uses the first delimiter pair in `tex.displayMath` and +`tex.inlineMath` to instead wrap math. + +#### `options.chtml` + +These options are passed to the [CommonHTML output +processor][mathjax-chtml-options]. +Passing `fontURL` is required! + +#### `options.svg` + +These options are passed to the [SVG output processor][mathjax-svg-options]. ## Security @@ -208,3 +219,7 @@ abide by its terms. [mathjax-chtml]: http://docs.mathjax.org/en/latest/output/html.html [mathjax-tex-options]: http://docs.mathjax.org/en/latest/options/input/tex.html + +[mathjax-svg-options]: http://docs.mathjax.org/en/latest/options/output/svg.html + +[mathjax-chtml-options]: http://docs.mathjax.org/en/latest/options/output/chtml.html diff --git a/packages/rehype-mathjax/svg.js b/packages/rehype-mathjax/svg.js index 54dbdcf..23fc64a 100644 --- a/packages/rehype-mathjax/svg.js +++ b/packages/rehype-mathjax/svg.js @@ -1,18 +1,15 @@ /** * @typedef {import('hast').Root} Root - * @typedef {import('./lib/create-plugin').SvgOptions} Options + * @typedef {import('mathjax-full/js/output/svg.js').SVG} SVG_ + * @typedef {import('./lib/create-plugin.js').Options} Options */ -import {createOutputSvg} from './lib/create-output-svg.js' +import {SVG} from 'mathjax-full/js/output/svg.js' import {createRenderer} from './lib/create-renderer.js' import {createPlugin} from './lib/create-plugin.js' -const rehypeMathJaxSvg = - /** @type {import('unified').Plugin<[Options?]|void[], Root>} */ - ( - createPlugin((inputOptions, outputOptions) => - createRenderer(inputOptions, createOutputSvg(outputOptions)) - ) - ) +const rehypeMathJaxSvg = createPlugin((options) => + createRenderer(options, new SVG(options.svg)) +) export default rehypeMathJaxSvg diff --git a/packages/rehype-mathjax/test/index.js b/packages/rehype-mathjax/test/index.js index 078ead8..c5c1c74 100644 --- a/packages/rehype-mathjax/test/index.js +++ b/packages/rehype-mathjax/test/index.js @@ -27,7 +27,12 @@ test('rehype-mathjax', (t) => { t.throws( () => { - unified().use(rehypeMathJaxChtml).freeze() + unified() + .use(rehypeParse, {fragment: true}) + .use(rehypeMathJaxChtml) + .use(rehypeStringify) + .processSync(readSync({dirname: fixtures, basename: 'small.html'})) + .toString() }, /rehype-mathjax: missing `fontURL` in options/, 'should crash for CHTML w/o `fontURL`' @@ -36,7 +41,7 @@ test('rehype-mathjax', (t) => { t.equal( unified() .use(rehypeParse, {fragment: true}) - .use(rehypeMathJaxChtml, {fontURL: 'place/to/fonts'}) + .use(rehypeMathJaxChtml, {chtml: {fontURL: 'place/to/fonts'}}) .use(rehypeStringify) .processSync(readSync({dirname: fixtures, basename: 'small.html'})) .toString(), @@ -105,8 +110,10 @@ test('rehype-mathjax', (t) => { unified() .use(rehypeParse, {fragment: true}) .use(rehypeMathJaxBrowser, { - inlineMath: ['$', '$'], - displayMath: ['$$', '$$'] + tex: { + inlineMath: [['$', '$']], + displayMath: [['$$', '$$']] + } }) .use(rehypeStringify) .processSync(readSync({dirname: fixtures, basename: 'small.html'})) @@ -165,7 +172,10 @@ test('rehype-mathjax', (t) => { t.equal( unified() .use(rehypeParse, {fragment: true}) - .use(rehypeMathJaxChtml, {fontURL: 'place/to/fonts', tex: {tags: 'ams'}}) + .use(rehypeMathJaxChtml, { + chtml: {fontURL: 'place/to/fonts'}, + tex: {tags: 'ams'} + }) .use(rehypeStringify) .processSync( readSync({