config, // This allows globally installing plugins even with eslint 6+ '--resolve-plugins-relative-to', strtok($stdout, "\n") ); } public function getLinterConfigurationOptions() { $options = array( 'config' => array( 'type' => 'optional string', 'help' => pht('Link to the config file.'), ), ); return $options + parent::getLinterConfigurationOptions(); } public function setLinterConfigurationValue($key, $value) { switch ($key) { case 'config': $this->config = $value; return; } return parent::setLinterConfigurationValue($key, $value); } protected function parseLinterOutput($path, $err, $stdout, $stderr) { // Gate on $stderr b/c $err (exit code) is expected. if ($stderr) { return false; } $json = json_decode($stdout, true); $messages = array(); foreach ($json as $file) { foreach ($file['messages'] as $offense) { // Skip file ignored warning: if a file is ignored by .eslintingore // but linted explicitly (by arcanist), a warning will be reported, // containing only: `{fatal:false,severity:1,message:...}`. if (strpos($offense['message'], "File ignored ") === 0) { continue; } $message = new ArcanistLintMessage(); $message->setPath($file['filePath']); $message->setSeverity($this->mapSeverity(idx($offense, 'severity', '0'))); $message->setName(nonempty(idx($offense, 'ruleId'), 'unknown')); $message->setDescription(idx($offense, 'message')); $message->setLine(idx($offense, 'line')); $message->setChar(idx($offense, 'column')); $message->setCode($this->getLinterName()); $messages[] = $message; } } return $messages; } private function mapSeverity($eslintSeverity) { switch($eslintSeverity) { case '0': return ArcanistLintSeverity::SEVERITY_ADVICE; case '1': return ArcanistLintSeverity::SEVERITY_WARNING; case '2': default: return ArcanistLintSeverity::SEVERITY_ERROR; } } }