diff --git a/packages/babel-code-frame/README.md b/packages/babel-code-frame/README.md index b9a5c6ca34..ca6f5c1664 100644 --- a/packages/babel-code-frame/README.md +++ b/packages/babel-code-frame/README.md @@ -30,3 +30,11 @@ console.log(result); | ^ 3 | } ``` + +If the column number is not known, you may pass `null` instead. + +## Options + +name | type | default | description +-----------------------|----------|-----------------|------------------------------------------------------ +highlightCode | boolean | `false` | Syntax highlight the code as JavaScript for terminals diff --git a/packages/babel-code-frame/src/index.js b/packages/babel-code-frame/src/index.js index 4d260b65eb..928874b611 100644 --- a/packages/babel-code-frame/src/index.js +++ b/packages/babel-code-frame/src/index.js @@ -1,16 +1,8 @@ -/* eslint indent: 0 */ -/* eslint max-len: 0 */ - -//import lineNumbers from "line-numbers"; import repeating from "repeating"; import jsTokens from "js-tokens"; import esutils from "esutils"; import chalk from "chalk"; -function lineNumbers(lines) { - return lines; -} - /** * Chalk styles for token types. */ @@ -46,15 +38,15 @@ function getTokenType(match) { if (token.type === "punctuator") { switch (token.value) { - case "{": - case "}": - return "curly"; - case "(": - case ")": - return "parens"; - case "[": - case "]": - return "square"; + case "{": + case "}": + return "curly"; + case "(": + case ")": + return "parens"; + case "[": + case "]": + return "square"; } } @@ -84,7 +76,7 @@ function highlight(text: string) { export default function ( rawLines: string, lineNumber: number, - colNumber: number, + colNumber: ?number, opts: Object = {}, ): string { colNumber = Math.max(colNumber, 0); @@ -101,20 +93,19 @@ export default function ( end = lines.length; } - let frame = lineNumbers(lines.slice(start, end), { - start: start + 1, - before: " ", - after: " | ", - transform(params) { - if (params.number !== lineNumber) { - return; - } + let numberMaxWidth = String(end).length; - if (colNumber) { - params.line += `\n${params.before}${repeating(" ", params.width)}${params.after}${repeating(" ", colNumber - 1)}^`; - } - - params.before = params.before.replace(/^./, ">"); + let frame = lines.slice(start, end).map((line, index) => { + let number = start + 1 + index; + let paddedNumber = ` ${number}`.slice(-numberMaxWidth); + let gutter = ` ${paddedNumber} | `; + if (number === lineNumber) { + let markerLine = colNumber + ? `\n ${gutter.replace(/\d/g, " ")}${repeating(" ", colNumber - 1)}^` + : ""; + return `>${gutter}${line}${markerLine}`; + } else { + return ` ${gutter}${line}`; } }).join("\n"); diff --git a/packages/babel-code-frame/test/index.js b/packages/babel-code-frame/test/index.js index 02a36f9f8e..6027130307 100644 --- a/packages/babel-code-frame/test/index.js +++ b/packages/babel-code-frame/test/index.js @@ -1,5 +1,106 @@ -var buildCodeFrame = require(".."); +var assert = require("assert"); +var chalk = require("chalk"); +var codeFrame = require(".."); suite("babel-code-frame", function () { + test("basic usage", function () { + const rawLines = [ + "class Foo {", + " constructor()", + "};", + ].join('\n'); + assert.equal(codeFrame(rawLines, 2, 16), [ + " 1 | class Foo {", + "> 2 | constructor()", + " | ^", + " 3 | };", + ].join('\n')); + }); + test("optional column number", function () { + const rawLines = [ + "class Foo {", + " constructor()", + "};", + ].join('\n'); + assert.equal(codeFrame(rawLines, 2, null), [ + " 1 | class Foo {", + "> 2 | constructor()", + " 3 | };", + ].join("\n")); + }); + + test("optional column number", function () { + const rawLines = [ + "class Foo {", + " constructor()", + "};", + ].join("\n"); + assert.equal(codeFrame(rawLines, 2, null), [ + " 1 | class Foo {", + "> 2 | constructor()", + " 3 | };", + ].join("\n")); + }); + + test("maximum context lines and padding", function () { + const rawLines = [ + "/**", + " * Sums two numbers.", + " *", + " * @param a Number", + " * @param b Number", + " * @returns Number", + " */", + "", + "function sum(a, b) {", + " return a + b", + "}" + ].join("\n"); + assert.equal(codeFrame(rawLines, 7, 2), [ + " 5 | * @param b Number", + " 6 | * @returns Number", + "> 7 | */", + " | ^", + " 8 | ", + " 9 | function sum(a, b) {", + " 10 | return a + b", + ].join("\n")); + }); + + test("no unnecessary padding due to one-off errors", function () { + const rawLines = [ + "/**", + " * Sums two numbers.", + " *", + " * @param a Number", + " * @param b Number", + " * @returns Number", + " */", + "", + "function sum(a, b) {", + " return a + b", + "}" + ].join("\n"); + assert.equal(codeFrame(rawLines, 6, 2), [ + " 4 | * @param a Number", + " 5 | * @param b Number", + "> 6 | * @returns Number", + " | ^", + " 7 | */", + " 8 | ", + " 9 | function sum(a, b) {", + ].join("\n")); + }); + + test("opts.highlightCode", function () { + const rawLines = "console.log('babel')"; + const result = codeFrame(rawLines, 1, 9, {highlightCode: true}) + const stripped = chalk.stripColor(result); + assert.ok(result.length > stripped.length); + assert.equal(stripped, [ + "> 1 | console.log('babel')", + " | ^", + ].join("\n")) + }); });