]>
Commit | Line | Data |
---|---|---|
0ab4d181 MD |
1 | # frozen_string_literal: true |
2 | ||
9be00a32 | 3 | require 'pronto' |
2950a68a | 4 | require 'shellwords' |
9be00a32 MM |
5 | |
6 | module Pronto | |
5001cb27 | 7 | class ESLintNpm < Runner |
1845f2e3 | 8 | CONFIG_FILE = '.pronto_eslint_npm.yml'.freeze |
0ab4d181 | 9 | CONFIG_KEYS = %w[eslint_executable files_to_lint].freeze |
3403f9d1 | 10 | |
1845f2e3 MD |
11 | attr_writer :eslint_executable |
12 | ||
13 | def eslint_executable | |
0ab4d181 | 14 | @eslint_executable || 'eslint' |
1845f2e3 MD |
15 | end |
16 | ||
17 | def files_to_lint | |
18 | @files_to_lint || /(\.js|\.es6)$/ | |
19 | end | |
20 | ||
21 | def files_to_lint=(regexp) | |
22 | @files_to_lint = regexp.is_a?(Regexp) && regexp || Regexp.new(regexp) | |
23 | end | |
24 | ||
c89a62b8 MD |
25 | def config_options |
26 | @config_options ||= | |
27 | begin | |
28 | config_file = File.join(repo_path, CONFIG_FILE) | |
29 | File.exist?(config_file) && YAML.load_file(config_file) || {} | |
30 | end | |
31 | end | |
3403f9d1 | 32 | |
c89a62b8 MD |
33 | def read_config |
34 | config_options.each do |key, val| | |
35 | next unless CONFIG_KEYS.include?(key.to_s) | |
36 | send("#{key}=", val) | |
3403f9d1 MD |
37 | end |
38 | end | |
39 | ||
b338a7ad | 40 | def run |
1845f2e3 MD |
41 | return [] if !@patches || @patches.count.zero? |
42 | ||
43 | read_config | |
9be00a32 | 44 | |
3403f9d1 MD |
45 | @patches |
46 | .select { |patch| patch.additions > 0 } | |
9be00a32 MM |
47 | .select { |patch| js_file?(patch.new_file_full_path) } |
48 | .map { |patch| inspect(patch) } | |
49 | .flatten.compact | |
50 | end | |
51 | ||
3403f9d1 MD |
52 | private |
53 | ||
1845f2e3 | 54 | def repo_path |
c89a62b8 | 55 | @repo_path ||= @patches.first.repo.path |
1845f2e3 | 56 | end |
29509625 | 57 | |
1845f2e3 | 58 | def inspect(patch) |
156f8167 MD |
59 | offences = run_eslint(patch) |
60 | clean_up_eslint_output(offences) | |
61 | .map do |offence| | |
62 | patch | |
63 | .added_lines | |
64 | .select { |line| line.new_lineno == offence['line'] } | |
65 | .map { |line| new_message(offence, line) } | |
29509625 | 66 | end |
9be00a32 MM |
67 | end |
68 | ||
69 | def new_message(offence, line) | |
0ab4d181 | 70 | path = line.patch.delta.new_file[:path] |
9be00a32 MM |
71 | level = :warning |
72 | ||
b338a7ad | 73 | Message.new(path, line, level, offence['message'], nil, self.class) |
9be00a32 MM |
74 | end |
75 | ||
76 | def js_file?(path) | |
1845f2e3 | 77 | files_to_lint =~ path.to_s |
9be00a32 | 78 | end |
156f8167 MD |
79 | |
80 | def run_eslint(patch) | |
1845f2e3 | 81 | Dir.chdir(repo_path) do |
c89a62b8 | 82 | JSON.parse `#{eslint_command_line(patch.new_file_full_path.to_s)}` |
156f8167 MD |
83 | end |
84 | end | |
85 | ||
c89a62b8 MD |
86 | def eslint_command_line(path) |
87 | "#{eslint_executable} #{Shellwords.escape(path)} -f json" | |
88 | end | |
89 | ||
156f8167 MD |
90 | def clean_up_eslint_output(output) |
91 | # 1. Filter out offences without a warning or error | |
92 | # 2. Get the messages for that file | |
93 | # 3. Ignore errors without a line number for now | |
94 | output | |
95 | .select { |offence| offence['errorCount'] + offence['warningCount'] > 0 } | |
96 | .map { |offence| offence['messages'] } | |
97 | .flatten.select { |offence| offence['line'] } | |
98 | end | |
9be00a32 MM |
99 | end |
100 | end |