code-excerpt.js 1.5 KB

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