Skip to content

Commit 476aa44

Browse files
committed
improve syntax highlighting in error messages
- Support hexadecimal, octal and binary number literals, template strings, and tokenize everything more robustly in general. - Tokens spanning over several lines (such as multiline strings and comments) no longer leak their color into the line number gutter. - The color scheme is preserved. - The line numbers are now right-aligned instead of left-aligned, since that's how practically every editor does it. - Superfluos space in the line number gutter has been removed.
1 parent c5589e9 commit 476aa44

File tree

2 files changed

+63
-50
lines changed

2 files changed

+63
-50
lines changed

lib/babel/helpers/code-frame.js

+60-49
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,57 @@
1-
// syntax highlighting based on https://github.com/dominictarr/ansi-highlight by the fantastic Dominic Tarr
2-
3-
var repeating = require("repeating");
4-
var tokenize = require("js-tokenizer");
5-
var chalk = require("chalk");
1+
var repeating = require("repeating");
2+
var jsTokens = require("js-tokens");
3+
var isJSKeyword = require("is-keyword-js");
4+
var chalk = require("chalk");
5+
var lineNumbers = require("line-numbers");
6+
var ary = require("lodash/function/ary");
67

78
var defs = {
8-
string1: "red",
9-
string2: "red",
10-
punct: ["white", "bold"],
11-
curly: "green",
12-
parens: ["blue", "bold"],
13-
square: ["yellow"],
14-
name: "white",
15-
keyword: ["cyan"],
16-
number: "magenta",
17-
regexp: "magenta",
18-
comment1: "grey",
19-
comment2: "grey"
9+
string: chalk.red,
10+
punctuation: chalk.white.bold,
11+
operator: chalk.white.bold,
12+
curly: chalk.green,
13+
parens: chalk.blue.bold,
14+
square: chalk.yellow,
15+
name: chalk.white,
16+
keyword: chalk.cyan,
17+
number: chalk.magenta,
18+
regex: chalk.magenta,
19+
comment: chalk.grey,
20+
invalid: chalk.inverse
2021
};
2122

22-
var highlight = function (text) {
23-
var colorize = function (str, col) {
24-
if (!col) return str;
23+
var newline = /\r\n|[\n\r\u2028\u2029]/;
2524

26-
if (Array.isArray(col)) {
27-
col.forEach(function (col) {
28-
str = chalk[col](str);
29-
});
30-
} else {
31-
str = chalk[col](str);
25+
var highlight = function (text) {
26+
var tokenType = function (match) {
27+
var token = jsTokens.matchToToken(match);
28+
if (token.type === "name" && isJSKeyword(token.value)) {
29+
return "keyword";
3230
}
33-
return str;
31+
if (token.type === "punctuation") {
32+
switch (token.value) {
33+
case "{":
34+
case "}":
35+
return "curly";
36+
case "(":
37+
case ")":
38+
return "parens";
39+
case "[":
40+
case "]":
41+
return "square";
42+
}
43+
}
44+
return token.type;
3445
};
3546

36-
return tokenize(text, true).map(function (str) {
37-
var type = tokenize.type(str);
38-
return colorize(str, defs[type]);
39-
}).join("");
47+
return text.replace(jsTokens, function (match) {
48+
var type = tokenType(arguments);
49+
if (type in defs) {
50+
var colorize = ary(defs[type], 1);
51+
return match.split(newline).map(colorize).join("\n");
52+
}
53+
return match;
54+
});
4055
};
4156

4257
module.exports = function (lines, lineNumber, colNumber) {
@@ -46,33 +61,29 @@ module.exports = function (lines, lineNumber, colNumber) {
4661
lines = highlight(lines);
4762
}
4863

49-
lines = lines.split(/\r\n|[\n\r\u2028\u2029]/);
64+
lines = lines.split(newline);
5065

5166
var start = Math.max(lineNumber - 3, 0);
5267
var end = Math.min(lines.length, lineNumber + 3);
53-
var width = (end + "").length;
5468

5569
if (!lineNumber && !colNumber) {
5670
start = 0;
5771
end = lines.length;
5872
}
5973

60-
return "\n" + lines.slice(start, end).map(function (line, i) {
61-
var curr = i + start + 1;
62-
63-
var gutter = curr === lineNumber ? "> " : " ";
64-
65-
var sep = curr + repeating(" ", width + 1);
66-
gutter += sep + "| ";
67-
68-
var str = gutter + line;
69-
70-
if (colNumber && curr === lineNumber) {
71-
str += "\n";
72-
str += repeating(" ", gutter.length - 2);
73-
str += "|" + repeating(" ", colNumber) + "^";
74+
return "\n" + lineNumbers(lines.slice(start, end), {
75+
start: start + 1,
76+
before: " ",
77+
after: " | ",
78+
transform: function (params) {
79+
if (params.number !== lineNumber) {
80+
return;
81+
}
82+
if (colNumber) {
83+
params.line += "\n" + params.before + repeating(" ", params.width) +
84+
params.after + repeating(" ", colNumber - 1) + "^";
85+
}
86+
params.before = params.before.replace(/^./, ">");
7487
}
75-
76-
return str;
7788
}).join("\n");
7889
};

package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,10 @@
4949
"fs-readdir-recursive": "^0.1.0",
5050
"globals": "^6.2.0",
5151
"is-integer": "^1.0.4",
52-
"js-tokenizer": "^1.3.3",
52+
"is-keyword-js": "^1.0.3",
53+
"js-tokens": "~0.4.1",
5354
"leven": "^1.0.1",
55+
"line-numbers": "~0.2.0",
5456
"lodash": "^3.2.0",
5557
"output-file-sync": "^1.1.0",
5658
"path-is-absolute": "^1.0.0",

0 commit comments

Comments
 (0)