* This is the ParseError class, which is the main error thrown by KaTeX * functions when something has gone wrong. This is used to distinguish internal * errors from errors in the expression that the user provided. * * If possible, a caller should provide a Token or ParseNode with information *
| 11 | * about where in the source string the problem occurred. |
| 12 | */ |
| 13 | class ParseError extends Error { |
| 14 | override name = "ParseError" as const; |
| 15 | position: number | undefined; |
| 16 | // Error start position based on passed-in Token or ParseNode. |
| 17 | length: number | undefined; |
| 18 | // Length of affected text based on passed-in Token or ParseNode. |
| 19 | rawMessage: string; |
| 20 | // The underlying error message without any context added. |
| 21 | |
| 22 | constructor( |
| 23 | message: string, // The error message |
| 24 | token?: Token | null | undefined | AnyParseNode, |
| 25 | ) { |
| 26 | let error = "KaTeX parse error: " + message; |
| 27 | let start; |
| 28 | let end; |
| 29 | |
| 30 | const loc = token && token.loc; |
| 31 | if (loc && loc.start <= loc.end) { |
| 32 | // If we have the input and a position, make the error a bit fancier |
| 33 | |
| 34 | // Get the input |
| 35 | const input = loc.lexer.input; |
| 36 | |
| 37 | // Prepend some information |
| 38 | start = loc.start; |
| 39 | end = loc.end; |
| 40 | if (start === input.length) { |
| 41 | error += " at end of input: "; |
| 42 | } else { |
| 43 | error += " at position " + (start + 1) + ": "; |
| 44 | } |
| 45 | |
| 46 | // Underline token in question using combining underscores |
| 47 | const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332"); |
| 48 | |
| 49 | // Extract some context from the input and add it to the error |
| 50 | let left; |
| 51 | if (start > 15) { |
| 52 | left = "…" + input.slice(start - 15, start); |
| 53 | } else { |
| 54 | left = input.slice(0, start); |
| 55 | } |
| 56 | let right; |
| 57 | if (end + 15 < input.length) { |
| 58 | right = input.slice(end, end + 15) + "…"; |
| 59 | } else { |
| 60 | right = input.slice(end); |
| 61 | } |
| 62 | error += left + underlined + right; |
| 63 | |
| 64 | } |
| 65 | |
| 66 | super(error); |
| 67 | Object.setPrototypeOf(this, ParseError.prototype); |
| 68 | this.position = start; |
| 69 | if (start != null && end != null) { |
| 70 | this.length = end - start; |
nothing calls this directly
no outgoing calls
no test coverage detected