1 | // @flow
|
2 | import {Token} from "./Token";
|
3 |
|
4 | import type {AnyParseNode} from "./parseNode";
|
5 |
|
6 | /**
|
7 | * This is the ParseError class, which is the main error thrown by KaTeX
|
8 | * functions when something has gone wrong. This is used to distinguish internal
|
9 | * errors from errors in the expression that the user provided.
|
10 | *
|
11 | * If possible, a caller should provide a Token or ParseNode with information
|
12 | * about where in the source string the problem occurred.
|
13 | */
|
14 | class ParseError {
|
15 | position: number | void;
|
16 | // Error position based on passed-in Token or ParseNode.
|
17 |
|
18 | constructor(
|
19 | message: string, // The error message
|
20 | token?: ?Token | AnyParseNode, // An object providing position information
|
21 | ) {
|
22 | let error = "KaTeX parse error: " + message;
|
23 | let start;
|
24 |
|
25 | const loc = token && token.loc;
|
26 | if (loc && loc.start <= loc.end) {
|
27 | // If we have the input and a position, make the error a bit fancier
|
28 |
|
29 | // Get the input
|
30 | const input = loc.lexer.input;
|
31 |
|
32 | // Prepend some information
|
33 | start = loc.start;
|
34 | const end = loc.end;
|
35 | if (start === input.length) {
|
36 | error += " at end of input: ";
|
37 | } else {
|
38 | error += " at position " + (start + 1) + ": ";
|
39 | }
|
40 |
|
41 | // Underline token in question using combining underscores
|
42 | const underlined = input.slice(start, end).replace(/[^]/g, "$&\u0332");
|
43 |
|
44 | // Extract some context from the input and add it to the error
|
45 | let left;
|
46 | if (start > 15) {
|
47 | left = "…" + input.slice(start - 15, start);
|
48 | } else {
|
49 | left = input.slice(0, start);
|
50 | }
|
51 | let right;
|
52 | if (end + 15 < input.length) {
|
53 | right = input.slice(end, end + 15) + "…";
|
54 | } else {
|
55 | right = input.slice(end);
|
56 | }
|
57 | error += left + underlined + right;
|
58 |
|
59 | }
|
60 |
|
61 | // Some hackery to make ParseError a prototype of Error
|
62 | // See http://stackoverflow.com/a/8460753
|
63 | const self = new Error(error);
|
64 | self.name = "ParseError";
|
65 | // $FlowFixMe
|
66 | self.__proto__ = ParseError.prototype;
|
67 | // $FlowFixMe
|
68 | self.position = start;
|
69 | return self;
|
70 | }
|
71 | }
|
72 |
|
73 | // $FlowFixMe More hackery
|
74 | ParseError.prototype.__proto__ = Error.prototype;
|
75 |
|
76 | export default ParseError;
|