Skip to content
Permalink
Browse files

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.
  • Loading branch information
lydell committed Feb 21, 2015
1 parent c5589e9 commit 476aa44a90a1e5a75cea1d9461575925ad541718
Showing with 63 additions and 50 deletions.
  1. +60 −49 lib/babel/helpers/code-frame.js
  2. +3 −1 package.json
@@ -1,42 +1,57 @@
// syntax highlighting based on https://github.com/dominictarr/ansi-highlight by the fantastic Dominic Tarr

var repeating = require("repeating");
var tokenize = require("js-tokenizer");
var chalk = require("chalk");
var repeating = require("repeating");
var jsTokens = require("js-tokens");
var isJSKeyword = require("is-keyword-js");
var chalk = require("chalk");
var lineNumbers = require("line-numbers");
var ary = require("lodash/function/ary");

var defs = {
string1: "red",
string2: "red",
punct: ["white", "bold"],
curly: "green",
parens: ["blue", "bold"],
square: ["yellow"],
name: "white",
keyword: ["cyan"],
number: "magenta",
regexp: "magenta",
comment1: "grey",
comment2: "grey"
string: chalk.red,
punctuation: chalk.white.bold,
operator: chalk.white.bold,
curly: chalk.green,
parens: chalk.blue.bold,
square: chalk.yellow,
name: chalk.white,
keyword: chalk.cyan,
number: chalk.magenta,
regex: chalk.magenta,
comment: chalk.grey,
invalid: chalk.inverse
};

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

if (Array.isArray(col)) {
col.forEach(function (col) {
str = chalk[col](str);
});
} else {
str = chalk[col](str);
var highlight = function (text) {
var tokenType = function (match) {
var token = jsTokens.matchToToken(match);
if (token.type === "name" && isJSKeyword(token.value)) {
return "keyword";
}
return str;
if (token.type === "punctuation") {
switch (token.value) {
case "{":
case "}":
return "curly";
case "(":
case ")":
return "parens";
case "[":
case "]":
return "square";
}
}
return token.type;
};

return tokenize(text, true).map(function (str) {
var type = tokenize.type(str);
return colorize(str, defs[type]);
}).join("");
return text.replace(jsTokens, function (match) {
var type = tokenType(arguments);
if (type in defs) {
var colorize = ary(defs[type], 1);
return match.split(newline).map(colorize).join("\n");
}
return match;
});
};

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

lines = lines.split(/\r\n|[\n\r\u2028\u2029]/);
lines = lines.split(newline);

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

if (!lineNumber && !colNumber) {
start = 0;
end = lines.length;
}

return "\n" + lines.slice(start, end).map(function (line, i) {
var curr = i + start + 1;

var gutter = curr === lineNumber ? "> " : " ";

var sep = curr + repeating(" ", width + 1);
gutter += sep + "| ";

var str = gutter + line;

if (colNumber && curr === lineNumber) {
str += "\n";
str += repeating(" ", gutter.length - 2);
str += "|" + repeating(" ", colNumber) + "^";
return "\n" + lineNumbers(lines.slice(start, end), {
start: start + 1,
before: " ",
after: " | ",
transform: function (params) {
if (params.number !== lineNumber) {
return;
}
if (colNumber) {
params.line += "\n" + params.before + repeating(" ", params.width) +
params.after + repeating(" ", colNumber - 1) + "^";
}
params.before = params.before.replace(/^./, ">");
}

return str;
}).join("\n");
};
@@ -49,8 +49,10 @@
"fs-readdir-recursive": "^0.1.0",
"globals": "^6.2.0",
"is-integer": "^1.0.4",
"js-tokenizer": "^1.3.3",
"is-keyword-js": "^1.0.3",
"js-tokens": "~0.4.1",
"leven": "^1.0.1",
"line-numbers": "~0.2.0",
"lodash": "^3.2.0",
"output-file-sync": "^1.1.0",
"path-is-absolute": "^1.0.0",

0 comments on commit 476aa44

Please sign in to comment.
You can’t perform that action at this time.