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