Module: MilkTea::ErrorFormatter

Defined in:
lib/milk_tea/tooling/error_formatter.rb

Class Method Summary collapse

Class Method Details

.error_suggestion_lines(error, color, bold, reset) ⇒ Object



63
64
65
66
67
68
69
70
71
72
# File 'lib/milk_tea/tooling/error_formatter.rb', line 63

def self.error_suggestion_lines(error, color, bold, reset)
  suggestion = error.respond_to?(:suggestion) ? error.suggestion : nil
  return [] unless suggestion

  suggestions = suggestion.is_a?(Array) ? suggestion : [suggestion]
  suggestions.map do |s|
    label = color ? "#{bold}= help:#{reset}" : "= help:"
    "  #{label} #{s}"
  end
end

.format(error, path: nil, source: nil, color: true) ⇒ Object



5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/milk_tea/tooling/error_formatter.rb', line 5

def self.format(error, path: nil, source: nil, color: true)
  error_message = error.respond_to?(:message) ? error.message : error.to_s
  return error_message unless error.respond_to?(:line) && error.line
  return error_message unless error.respond_to?(:column) && error.column

  path ||= error.respond_to?(:path) ? error.path : nil
  return error_message unless path

  line = error.line.to_i
  column = error.column.to_i
  length = error.respond_to?(:length) ? error.length.to_i : 0
  severity = error.respond_to?(:severity) ? error.severity : :error
  code = error.respond_to?(:code) ? error.code : nil

  # Strip location suffix from message (errors embed "at path:line:col" in message text)
  location_suffix = " at #{path}:#{line}:#{column}"
  error_message = error_message.delete_suffix(location_suffix).strip

  source ||= read_source(path)

  bold  = color ? "\e[1m"  : ""
  red   = color ? "\e[31m" : ""
  yellow = color ? "\e[33m" : ""
  cyan  = color ? "\e[36m" : ""
  reset = color ? "\e[0m"  : ""

  sev_color, sev_text = case severity
                        when :error   then [red,    "error"]
                        when :warning then [yellow, "warning"]
                        when :info    then [cyan,   "info"]
                        when :hint    then [cyan,   "hint"]
                        else               [red,    "error"]
                        end

  code_text = code ? "#{cyan}[#{code}]#{reset}" : ""

  return "#{sev_color}#{sev_text}#{code_text}#{reset}: #{error_message} -- #{path}:#{line}:#{column}" unless source

  source_lines = source.split("\n", -1)
  source_line = source_lines[line - 1] || ""
  stripped = source_line.gsub(/\t/, " ")

  indent = " " * [column - 1, 0].max
  highlight = if length && length > 1
                "^" + "~" * (length - 1)
              else
                "^"
              end

  [
    "#{sev_color}#{sev_text}#{code_text}#{reset}: #{error_message} -- #{path}:#{line}:#{column}",
    "   #{bold}|#{reset}",
    "#{line.to_s.rjust(5)} #{bold}|#{reset} #{stripped}",
    "      #{bold}|#{reset} #{sev_color}#{indent}#{highlight}#{reset}",
    *error_suggestion_lines(error, color, bold, reset),
  ].join("\n")
end

.read_source(path) ⇒ Object



74
75
76
77
78
# File 'lib/milk_tea/tooling/error_formatter.rb', line 74

def self.read_source(path)
  File.read(path)
rescue Errno::ENOENT, Errno::EISDIR
  nil
end

.severity_label(severity) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'lib/milk_tea/tooling/error_formatter.rb', line 80

def self.severity_label(severity)
  case severity
  when :error   then "error"
  when :warning then "warning"
  when :info    then "info"
  when :hint    then "hint"
  else               "error"
  end
end