Skip to content

Commit

Permalink
Refactor to move code to lib/
Browse files Browse the repository at this point in the history
  • Loading branch information
wooorm committed Sep 18, 2023
1 parent e8039d7 commit 23914b6
Show file tree
Hide file tree
Showing 12 changed files with 216 additions and 199 deletions.
115 changes: 2 additions & 113 deletions packages/rehype-katex/index.js
Original file line number Diff line number Diff line change
@@ -1,116 +1,5 @@
/**
* @typedef {import('hast').ElementContent} ElementContent
* @typedef {import('hast').Root} Root
*
* @typedef {import('katex').KatexOptions} KatexOptions
*
* @typedef {import('vfile').VFile} VFile
* @typedef {import('./lib/index.js').Options} Options
*/

/**
* @typedef {Omit<KatexOptions, 'throwOnError'>} Options
*/

import {fromHtmlIsomorphic} from 'hast-util-from-html-isomorphic'
import {toText} from 'hast-util-to-text'
import katex from 'katex'
import {visit} from 'unist-util-visit'

/** @type {Readonly<Options>} */
const emptyOptions = {}
/** @type {ReadonlyArray<unknown>} */
const emptyClasses = []

/**
* Plugin to transform `<span class=math-inline>` and `<div class=math-display>`
* with KaTeX.
*
* @param {Readonly<Options> | null | undefined} [options]
* Configuration (optional).
* @returns
* Transform.
*/
export default function rehypeKatex(options) {
const settings = options || emptyOptions

/**
* Transform.
*
* @param {Root} tree
* Tree.
* @param {VFile} file
* File.
* @returns {undefined}
* Nothing.
*/
return function (tree, file) {
visit(tree, 'element', function (element, _, parent) {
const classes = Array.isArray(element.properties.className)
? element.properties.className
: emptyClasses
const inline = classes.includes('math-inline')
const displayMode = classes.includes('math-display')

if (!inline && !displayMode) {
return
}

const value = toText(element, {whitespace: 'pre'})

/** @type {string} */
let result

try {
result = katex.renderToString(value, {
...settings,
displayMode,
throwOnError: true
})
} catch (error) {
const cause = /** @type {Error} */ (error)
const ruleId = cause.name.toLowerCase()

file.message('Could not render math with KaTeX', {
/* c8 ignore next -- verbose to test */
ancestors: parent ? [parent, element] : [element],
cause,
place: element.position,
ruleId,
source: 'rehype-katex'
})

// KaTeX can handle `ParseError` itself, but not others.
if (ruleId === 'parseerror') {
result = katex.renderToString(value, {
...settings,
displayMode,
strict: 'ignore',
throwOnError: false
})
}
// Generate similar markup if this is an other error.
// See: <https://github.com/KaTeX/KaTeX/blob/5dc7af0/docs/error.md>.
else {
element.children = [
{
type: 'element',
tagName: 'span',
properties: {
className: ['katex-error'],
style: 'color:' + (settings.errorColor || '#cc0000'),
title: String(error)
},
children: [{type: 'text', value}]
}
]
return
}
}

const root = fromHtmlIsomorphic(result, {fragment: true})
// Cast because there will not be `doctypes` in KaTeX result.
const content = /** @type {Array<ElementContent>} */ (root.children)
element.children = content
})
}
}
export {default} from './lib/index.js'
116 changes: 116 additions & 0 deletions packages/rehype-katex/lib/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
/**
* @typedef {import('hast').ElementContent} ElementContent
* @typedef {import('hast').Root} Root
*
* @typedef {import('katex').KatexOptions} KatexOptions
*
* @typedef {import('vfile').VFile} VFile
*/

/**
* @typedef {Omit<KatexOptions, 'throwOnError'>} Options
*/

import {fromHtmlIsomorphic} from 'hast-util-from-html-isomorphic'
import {toText} from 'hast-util-to-text'
import katex from 'katex'
import {visit} from 'unist-util-visit'

/** @type {Readonly<Options>} */
const emptyOptions = {}
/** @type {ReadonlyArray<unknown>} */
const emptyClasses = []

/**
* Plugin to transform `<span class=math-inline>` and `<div class=math-display>`
* with KaTeX.
*
* @param {Readonly<Options> | null | undefined} [options]
* Configuration (optional).
* @returns
* Transform.
*/
export default function rehypeKatex(options) {
const settings = options || emptyOptions

/**
* Transform.
*
* @param {Root} tree
* Tree.
* @param {VFile} file
* File.
* @returns {undefined}
* Nothing.
*/
return function (tree, file) {
visit(tree, 'element', function (element, _, parent) {
const classes = Array.isArray(element.properties.className)
? element.properties.className
: emptyClasses
const inline = classes.includes('math-inline')
const displayMode = classes.includes('math-display')

if (!inline && !displayMode) {
return
}

const value = toText(element, {whitespace: 'pre'})

/** @type {string} */
let result

try {
result = katex.renderToString(value, {
...settings,
displayMode,
throwOnError: true
})
} catch (error) {
const cause = /** @type {Error} */ (error)
const ruleId = cause.name.toLowerCase()

file.message('Could not render math with KaTeX', {
/* c8 ignore next -- verbose to test */
ancestors: parent ? [parent, element] : [element],
cause,
place: element.position,
ruleId,
source: 'rehype-katex'
})

// KaTeX can handle `ParseError` itself, but not others.
if (ruleId === 'parseerror') {
result = katex.renderToString(value, {
...settings,
displayMode,
strict: 'ignore',
throwOnError: false
})
}
// Generate similar markup if this is an other error.
// See: <https://github.com/KaTeX/KaTeX/blob/5dc7af0/docs/error.md>.
else {
element.children = [
{
type: 'element',
tagName: 'span',
properties: {
className: ['katex-error'],
style: 'color:' + (settings.errorColor || '#cc0000'),
title: String(error)
},
children: [{type: 'text', value}]
}
]
return
}
}

const root = fromHtmlIsomorphic(result, {fragment: true})
// Cast because there will not be `doctypes` in KaTeX result.
const content = /** @type {Array<ElementContent>} */ (root.children)
element.children = content
})
}
}
1 change: 1 addition & 0 deletions packages/rehype-katex/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"main": "index.js",
"types": "index.d.ts",
"files": [
"lib/",
"index.d.ts",
"index.js"
],
Expand Down
22 changes: 1 addition & 21 deletions packages/rehype-mathjax/browser.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,5 @@
/**
* @typedef {import('./lib/create-plugin.js').Options} Options
* @typedef {import('./lib/create-plugin.js').InputTexOptions} InputTexOptions
*/

import {createPlugin} from './lib/create-plugin.js'

/** @type {Readonly<InputTexOptions>} */
const emptyTexOptions = {}

const rehypeMathJaxBrowser = createPlugin(function (options) {
const tex = options.tex || emptyTexOptions
const display = tex.displayMath || [['\\[', '\\]']]
const inline = tex.inlineMath || [['\\(', '\\)']]

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
export {default} from './lib/browser.js'
16 changes: 1 addition & 15 deletions packages/rehype-mathjax/chtml.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,4 @@
* @typedef {import('./lib/create-plugin.js').Options} Options
*/

import {CHTML} from 'mathjax-full/js/output/chtml.js'
import {createPlugin} from './lib/create-plugin.js'
import {createRenderer} from './lib/create-renderer.js'

const rehypeMathJaxCHtml = createPlugin(function (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
export {default} from './lib/chtml.js'
2 changes: 1 addition & 1 deletion packages/rehype-mathjax/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
* @typedef {import('./lib/create-plugin.js').Options} Options
*/

export {default} from './svg.js'
export {default} from './lib/svg.js'
24 changes: 24 additions & 0 deletions packages/rehype-mathjax/lib/browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* @typedef {import('./create-plugin.js').InputTexOptions} InputTexOptions
*/

import {createPlugin} from './create-plugin.js'

/** @type {Readonly<InputTexOptions>} */
const emptyTexOptions = {}

const rehypeMathJaxBrowser = createPlugin(function (options) {
const tex = options.tex || emptyTexOptions
const display = tex.displayMath || [['\\[', '\\]']]
const inline = tex.inlineMath || [['\\(', '\\)']]

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
15 changes: 15 additions & 0 deletions packages/rehype-mathjax/lib/chtml.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {CHTML} from 'mathjax-full/js/output/chtml.js'
import {createPlugin} from './create-plugin.js'
import {createRenderer} from './create-renderer.js'

const rehypeMathJaxCHtml = createPlugin(function (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
10 changes: 10 additions & 0 deletions packages/rehype-mathjax/lib/svg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import {SVG} from 'mathjax-full/js/output/svg.js'
import {createPlugin} from './create-plugin.js'
import {createRenderer} from './create-renderer.js'

const rehypeMathJaxSvg = createPlugin(function (options) {
// MathJax types do not allow `null`.
return createRenderer(options, new SVG(options.svg || undefined))
})

export default rehypeMathJaxSvg
11 changes: 1 addition & 10 deletions packages/rehype-mathjax/svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,4 @@
* @typedef {import('./lib/create-plugin.js').Options} Options
*/

import {SVG} from 'mathjax-full/js/output/svg.js'
import {createPlugin} from './lib/create-plugin.js'
import {createRenderer} from './lib/create-renderer.js'

const rehypeMathJaxSvg = createPlugin(function (options) {
// `mathjax-types` do not allow `null`.
return createRenderer(options, new SVG(options.svg || undefined))
})

export default rehypeMathJaxSvg
export {default} from './lib/svg.js'
Loading

0 comments on commit 23914b6

Please sign in to comment.