Changeset View
Changeset View
Standalone View
Standalone View
src/lint/linter/ArcanistESLintLinter.php
- This file was added.
<?php | |||||
/** | |||||
* Uses ESLint to detect errors and potential problems in JavaScript code. | |||||
*/ | |||||
final class ArcanistESLintLinter extends ArcanistExternalLinter { | |||||
private $eslintignore; | |||||
private $eslintrc; | |||||
public function getInfoName() { | |||||
return 'Pluggable JavaScript linter'; | |||||
} | |||||
public function getInfoURI() { | |||||
return 'http://eslint.org/'; | |||||
} | |||||
public function getInfoDescription() { | |||||
return pht( | |||||
'Use `%s` to detect issues with JavaScript source files.', | |||||
'eslint'); | |||||
} | |||||
public function getLinterName() { | |||||
return 'ESLint'; | |||||
} | |||||
public function getLinterConfigurationName() { | |||||
return 'eslint'; | |||||
} | |||||
protected function getDefaultMessageSeverity($code) { | |||||
if ($code == 1) { | |||||
return ArcanistLintSeverity::SEVERITY_WARNING; | |||||
} else { | |||||
return ArcanistLintSeverity::SEVERITY_ERROR; | |||||
} | |||||
} | |||||
public function getDefaultBinary() { | |||||
return 'eslint'; | |||||
} | |||||
public function getVersion() { | |||||
list($stdout, $stderr) = execx( | |||||
'%C --version', | |||||
$this->getExecutableCommand()); | |||||
$matches = array(); | |||||
$regex = '/^v(?P<version>\d+\.\d+\.\d+)$/'; | |||||
if (preg_match($regex, $stdout, $matches)) { | |||||
return $matches['version']; | |||||
} else { | |||||
return false; | |||||
} | |||||
} | |||||
public function getInstallInstructions() { | |||||
return pht('Install ESLint using `%s`.', 'npm install -g eslint'); | |||||
} | |||||
protected function getMandatoryFlags() { | |||||
$options = array(); | |||||
$options[] = '--format=json'; | |||||
if ($this->eslintrc) { | |||||
$options[] = '--config='.$this->eslintrc; | |||||
} | |||||
if ($this->eslintignore) { | |||||
$options[] = '--ignore-path='.$this->eslintignore; | |||||
} | |||||
return $options; | |||||
} | |||||
public function getLinterConfigurationOptions() { | |||||
$options = array( | |||||
'eslint.eslintignore' => array( | |||||
'type' => 'optional string', | |||||
'help' => pht('Pass in a custom eslintignore file path.'), | |||||
), | |||||
'eslint.eslintrc' => array( | |||||
'type' => 'optional string', | |||||
'help' => pht('Custom configuration file.'), | |||||
), | |||||
); | |||||
return $options + parent::getLinterConfigurationOptions(); | |||||
} | |||||
public function setLinterConfigurationValue($key, $value) { | |||||
switch ($key) { | |||||
case 'eslint.eslintignore': | |||||
$this->eslintignore = $value; | |||||
return; | |||||
case 'eslint.eslintrc': | |||||
$this->eslintrc = $value; | |||||
return; | |||||
} | |||||
return parent::setLinterConfigurationValue($key, $value); | |||||
} | |||||
protected function parseLinterOutput($path, $err, $stdout, $stderr) { | |||||
$errors = null; | |||||
try { | |||||
$errors = phutil_json_decode($stdout); | |||||
} catch (PhutilJSONParserException $ex) { | |||||
// Something went wrong and we can't decode the output. Exit abnormally. | |||||
throw new PhutilProxyException( | |||||
pht('ESLint returned unparseable output.'), | |||||
$ex); | |||||
} | |||||
$messages = array(); | |||||
foreach (idx($errors[0], 'messages') as $err) { | |||||
$message = new ArcanistLintMessage(); | |||||
$message->setPath($path); | |||||
$message->setLine(idx($err, 'line')); | |||||
$message->setChar(idx($err, 'column')); | |||||
$message->setDescription(idx($err, 'message')); | |||||
$message->setSeverity( | |||||
$this->getLintMessageSeverity(idx($err, 'severity'))); | |||||
// In case of a parsing error, eslint does not specify what rule failed | |||||
// Instead it sets fatal to true | |||||
if (idx($err, 'fatal')) { | |||||
$message->setCode('fatal'); | |||||
$message->setName('ParsingError'); | |||||
} else { | |||||
$message->setCode(idx($err, 'ruleId')); | |||||
$message->setName(idx($err, 'nodeType')); | |||||
} | |||||
$messages[] = $message; | |||||
} | |||||
return $messages; | |||||
} | |||||
protected function getLintCodeFromLinterConfigurationKey($code) { | |||||
return $code; | |||||
} | |||||
} |