1 | 'use strict';
|
2 | const fs = require('fs');
|
3 | const equalLength = require('equal-length');
|
4 | const codeExcerpt = require('code-excerpt');
|
5 | const truncate = require('cli-truncate');
|
6 | const chalk = require('./chalk').get();
|
7 |
|
8 | const formatLineNumber = (lineNumber, maxLineNumber) =>
|
9 | ' '.repeat(Math.max(0, String(maxLineNumber).length - String(lineNumber).length)) + lineNumber;
|
10 |
|
11 | module.exports = (source, options = {}) => {
|
12 | if (!source.isWithinProject || source.isDependency) {
|
13 | return null;
|
14 | }
|
15 |
|
16 | const {file, line} = source;
|
17 | const maxWidth = options.maxWidth || 80;
|
18 |
|
19 | let contents;
|
20 | try {
|
21 | contents = fs.readFileSync(file, 'utf8');
|
22 | } catch {
|
23 | return null;
|
24 | }
|
25 |
|
26 | const excerpt = codeExcerpt(contents, line, {around: 1});
|
27 | if (!excerpt) {
|
28 | return null;
|
29 | }
|
30 |
|
31 | const lines = excerpt.map(item => ({
|
32 | line: item.line,
|
33 | value: truncate(item.value, maxWidth - String(line).length - 5)
|
34 | }));
|
35 |
|
36 | const joinedLines = lines.map(line => line.value).join('\n');
|
37 | const extendedLines = equalLength(joinedLines).split('\n');
|
38 |
|
39 | return lines
|
40 | .map((item, index) => ({
|
41 | line: item.line,
|
42 | value: extendedLines[index]
|
43 | }))
|
44 | .map(item => {
|
45 | const isErrorSource = item.line === line;
|
46 |
|
47 | const lineNumber = formatLineNumber(item.line, line) + ':';
|
48 | const coloredLineNumber = isErrorSource ? lineNumber : chalk.grey(lineNumber);
|
49 | const result = ` ${coloredLineNumber} ${item.value}`;
|
50 |
|
51 | return isErrorSource ? chalk.bgRed(result) : result;
|
52 | })
|
53 | .join('\n');
|
54 | };
|