-
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Stop throwing ParseError when throwOnError is false #1169
Conversation
`render`, `renderToString`, etc. now catch ParseError and render it to the raw LaTeX (with proper escaping) and a hover title with the error. Along the way: * Use new `katex.__renderToDomTree` in katex-spec's `_getBuilt`. (This was necessary to get the new error handling in `_getBuilt`.) * Fix jest results which must always be functions, not strings.
Codecov Report
@@ Coverage Diff @@
## master #1169 +/- ##
==========================================
+ Coverage 83.76% 83.78% +0.01%
==========================================
Files 61 61
Lines 3978 3989 +11
Branches 662 663 +1
==========================================
+ Hits 3332 3342 +10
- Misses 547 548 +1
Partials 99 99
Continue to review full report at Codecov.
|
Leave error type unspecified, as we check it with instanceof.
How about using error levels: |
@edemaine thanks for the PR. This is definitely a pain point for users. I will review this weekend. |
@@ -98,10 +100,10 @@ const parseAndSetResult = function(expr, result, settings) { | |||
} catch (e) { | |||
result.pass = false; | |||
if (e instanceof ParseError) { | |||
result.message = "'" + expr + "' failed " + | |||
result.message = () => "'" + expr + "' failed " + | |||
"parsing with error: " + e.message; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did result.message
change to a callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is necessary since some update to Jest: Jest requires all messages to be callable. Obviously not directly related to this PR, but I ran into this (presumably long-standing) bug when my tests were failing.
`; | ||
|
||
exports[`A parser that does not throw on unsupported commands should properly escape LaTeX in errors 1`] = `"<span class=\\"katex-error\\" title=\\"ParseError: KaTeX parse error: Expected group after '^' at position 2: 2^̲&"<>\\" style=\\"color:#933\\">2^&"<></span>"`; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice
static/main.js
Outdated
@@ -21,7 +21,7 @@ function init() { | |||
const macros = {}; | |||
// TODO: Add toggle for displayMode. | |||
// https://github.com/Khan/KaTeX/issues/1035 | |||
const options = {displayMode: true}; | |||
const options = {displayMode: true, throwOnError: false}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool.
options: Settings, | ||
) { | ||
if (options.throwOnError || !(error instanceof ParseError)) { | ||
throw error; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does re-throwing maintain the call stack?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kevinbarabash Yes 😄
* renders the invalid LaTeX as a span with hover title giving the KaTeX | ||
* error message. Otherwise, simply throws the error. | ||
*/ | ||
const renderError = function( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a really slick solution.
I can't think of a situation where people would actually want level 1. They'd still need to use a try/catch to avoid errors other than unsupported command errors. |
@kevinbarabash A user may want to implement custom error handler, but in the custom error handler, it cannot access KaTeX internals, i.e., if it's unsupported command error print the plain command name. Though as you said, I'm not sure there are people want it. |
I could see wanting to build a custom handler for custom formatting in the error case. An alternative would be to provide a callback to call instead of an error handler. Maybe |
With #1226, I think we should have an error callback function(handler) and handle errors accordingly. |
@edemaine looks like there's some lint:
|
Thanks for the review, @ylemkimon. Do you think I should add an error callback function for custom error handling/rendering? Or leave that for consideration in another PR? |
Now I think currently there is no way to access KaTeX internals, and custom error handler probably should be another issue/PR. Thank you for the PR! |
Sounds good! By the way, this is a breaking change compared to old behavior (rendering instead of throwing an exception), so should we advance to 0.10? @kevinbarabash |
PR KaTeX#1169 forgot to document itself. This fixes the README accordingly.
PR #1169 forgot to document itself. This fixes the README accordingly.
This PR is motivated by the recent security issue reported in #1160. I would argue that almost anyone who uses KaTeX on a user-specified string doesn't want an exception to happen, but rather wants KaTeX to do its best job at rendering the given LaTeX.
throwOnError
is the obvious "solution", but it actually only fixes invalid commands, but any other type ofParseError
still gets thrown. This is nice because you get partial renderings, but not nice because it doesn't fix the original problem of not throwing exceptions. As a result, I believe many KaTeX users (myself included) write our owntry ... catch ...
block to render something else when KaTeX throws an error. And if done poorly, this leads to security holes like #1160.This PR makes
throwOnError
more useful by rendering HTML for all types ofParseError
. If it's just an unknown command, you get a partial render as before. But if you have some other type of error, you get a<span class="katex-error">
whose text is the LaTeX source code, its color isoptions.errorColor
(defaulting to red as usual), and it has a hover title that displays the actual error message. This is what I did in my own KaTeX error handler. Crucially, the output HTML is properly escaped (thanks to our existing domTree infrastructure -- see the test snapshot).There's an obvious alternative: show the error message directly, and hover to see the LaTeX. Or some other combination. But IMHO this PR is probably closest to the intent of the author: if you can't render nice LaTeX, at least render the source code.
Another question is naming. I took over
throwOnError
because it is the natural name for this feature (and probably what most people expect). But it breaks backwards compatibility, so would need to be a new version. We could use another name to keep backward compatibility. We could also provide the old behavior, via something likethrowOnBadCommand
. I'm not sure of a great use for this... If one wants to reformat the error style, they could use CSS, or (in the worst case) parse the resulting<span class="katex-error">
and restructure.Along the way:
katex.__renderToDomTree
in katex-spec's_getBuilt
. (This was necessary to get the new error handling in_getBuilt
.)