Skip to content

Commit

Permalink
Remove throwOnError option, improve message
Browse files Browse the repository at this point in the history
This improves KaTeX errors and removes the `throwOnError` option: messages
are always emitted as warnings.
  • Loading branch information
wooorm committed Sep 18, 2023
1 parent 2cc0743 commit 232f0d7
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 62 deletions.
40 changes: 25 additions & 15 deletions packages/rehype-katex/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
* @typedef {import('hast').ElementContent} ElementContent
* @typedef {import('hast').Root} Root
*
* @typedef {import('katex').KatexOptions} Options
* @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'
Expand All @@ -28,7 +32,6 @@ const emptyClasses = []
*/
export default function rehypeKatex(options) {
const settings = options || emptyOptions
const throwOnError = settings.throwOnError || false

/**
* Transform.
Expand All @@ -41,7 +44,7 @@ export default function rehypeKatex(options) {
* Nothing.
*/
return function (tree, file) {
visit(tree, 'element', function (element) {
visit(tree, 'element', function (element, _, parent) {
const classes = Array.isArray(element.properties.className)
? element.properties.className
: emptyClasses
Expand All @@ -64,16 +67,30 @@ export default function rehypeKatex(options) {
throwOnError: true
})
} catch (error) {
const exception = /** @type {Error} */ (error)
const fn = throwOnError ? 'fail' : 'message'
const origin = ['rehype-katex', exception.name.toLowerCase()].join(':')
const cause = /** @type {Error} */ (error)
const ruleId = cause.name.toLowerCase()

file[fn](exception.message, element.position, origin)
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>.
if (exception.name !== 'ParseError') {
else {
element.children = [
{
type: 'element',
Expand All @@ -88,13 +105,6 @@ export default function rehypeKatex(options) {
]
return
}

result = katex.renderToString(value, {
...settings,
displayMode,
strict: 'ignore',
throwOnError: false
})
}

const root = fromHtmlIsomorphic(result, {fragment: true})
Expand Down
5 changes: 0 additions & 5 deletions packages/rehype-katex/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,6 @@ Transform `<span class="math-inline">` and `<div class="math-display">` with
Configuration (optional).
All options, except for `displayMode`, are passed to [KaTeX][katex-options].

###### `options.throwOnError`

Throw if a KaTeX parse error occurs (`boolean`, default: `false`).
See [KaTeX options][katex-options].

## CSS

The HTML produced by KaTeX requires CSS to render correctly.
Expand Down
78 changes: 37 additions & 41 deletions packages/rehype-katex/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,15 +142,15 @@ test('rehype-katex', async function (t) {
)
})

await t.test('should support `errorColor`', async function () {
await t.test('should handle errors, support `errorColor`', async function () {
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeKatex, {errorColor: 'orange'})
.use(rehypeStringify)
.process('<code class="math-inline">\\alpa</code>')

assert.deepEqual(
String(
await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeKatex, {errorColor: 'orange'})
.use(rehypeStringify)
.process('<code class="math-inline">\\alpa</code>')
),
String(file),
String(
await unified()
.use(rehypeParse, {fragment: true})
Expand All @@ -165,41 +165,37 @@ test('rehype-katex', async function (t) {
)
)
)
})

await t.test('should create a message for errors', async function () {
const file = await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeKatex)
.use(rehypeStringify)
.process('<p>Lorem</p>\n<p><code class="math-inline">\\alpa</code></p>')

assert.deepEqual(file.messages.map(String), [
'2:4-2:42: KaTeX parse error: Undefined control sequence: \\alpa at position 1: \\̲a̲l̲p̲a̲'
])
})

await t.test(
'should throw an error if `throwOnError: true`',
async function () {
try {
await unified()
.use(rehypeParse, {fragment: true})
.use(rehypeKatex, {throwOnError: true})
.use(rehypeStringify)
.process(
'<p>Lorem</p>\n<p><code class="math-inline">\\alpa</code></p>'
)
/* c8 ignore next 2 -- some c8 bug. */
assert.fail()
} catch (error) {
assert.match(
String(error),
/KaTeX parse error: Undefined control sequence: \\alpa at position 1: \\̲a̲l̲p̲a̲/
)
assert.equal(file.messages.length, 1)
const message = file.messages[0]
assert(message)
assert(message.cause)
assert(message.ancestors)
assert.match(
String(message.cause),
/KaTeX parse error: Undefined control sequence/
)
assert.equal(message.ancestors.length, 2)
assert.deepEqual(
{...file.messages[0], cause: undefined, ancestors: []},
{
ancestors: [],
cause: undefined,
column: 1,
fatal: false,
line: 1,
message: 'Could not render math with KaTeX',
name: '1:1-1:39',
place: {
start: {column: 1, line: 1, offset: 0},
end: {column: 39, line: 1, offset: 38}
},
reason: 'Could not render math with KaTeX',
ruleId: 'parseerror',
source: 'rehype-katex'
}
}
)
)
})

await t.test('should support `strict: ignore`', async function () {
assert.deepEqual(
Expand Down
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"declaration": true,
"emitDeclarationOnly": true,
"exactOptionalPropertyTypes": true,
"lib": ["es2020"],
"lib": ["es2022"],
"module": "node16",
// To do: remove when `mathjax-full` types are fixed.
"skipLibCheck": true,
Expand Down

0 comments on commit 232f0d7

Please sign in to comment.