]> git.immae.eu Git - github/fretlink/pronto-hlint.git/blob - lib/pronto/eslint_npm.rb
refactor config handling and specs a little bit
[github/fretlink/pronto-hlint.git] / lib / pronto / eslint_npm.rb
1 # frozen_string_literal: true
2
3 require 'pronto'
4 require 'shellwords'
5
6 module Pronto
7 class ESLintNpm < Runner
8 CONFIG_FILE = '.pronto_eslint_npm.yml'.freeze
9 CONFIG_KEYS = %w[eslint_executable files_to_lint].freeze
10
11 attr_writer :eslint_executable
12
13 def eslint_executable
14 @eslint_executable || 'eslint'
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
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
32
33 def read_config
34 config_options.each do |key, val|
35 next unless CONFIG_KEYS.include?(key.to_s)
36 send("#{key}=", val)
37 end
38 end
39
40 def run
41 return [] if !@patches || @patches.count.zero?
42
43 read_config
44
45 @patches
46 .select { |patch| patch.additions > 0 }
47 .select { |patch| js_file?(patch.new_file_full_path) }
48 .map { |patch| inspect(patch) }
49 .flatten.compact
50 end
51
52 private
53
54 def repo_path
55 @repo_path ||= @patches.first.repo.path
56 end
57
58 def inspect(patch)
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) }
66 end
67 end
68
69 def new_message(offence, line)
70 path = line.patch.delta.new_file[:path]
71 level = :warning
72
73 Message.new(path, line, level, offence['message'], nil, self.class)
74 end
75
76 def js_file?(path)
77 files_to_lint =~ path.to_s
78 end
79
80 def run_eslint(patch)
81 Dir.chdir(repo_path) do
82 JSON.parse `#{eslint_command_line(patch.new_file_full_path.to_s)}`
83 end
84 end
85
86 def eslint_command_line(path)
87 "#{eslint_executable} #{Shellwords.escape(path)} -f json"
88 end
89
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
99 end
100 end