1
0
Fork 0
mirror of https://we.phorge.it/source/arcanist.git synced 2025-01-10 06:41:04 +01:00
phorge-arcanist/src/lint/linter/ArcanistLesscLinter.php
Joshua Spence 8244b3582a Improve behavior for detecting the failure to parse external linter output
Summary:
Currently, a lot of `ArcanistExternalLinter` subclasses have something like this:

```lang=php
if ($err && !$messages) {
  return false;
}
```

We can avoid this code duplication by moving this check to the `ArcanistExternalLinter` class.

Test Plan: `arc unit`

Reviewers: #blessed_reviewers, epriestley

Reviewed By: #blessed_reviewers, epriestley

Subscribers: Korvin, epriestley

Differential Revision: https://secure.phabricator.com/D11321
2015-05-22 07:30:17 +10:00

183 lines
4.8 KiB
PHP

<?php
/**
* A linter for LESSCSS files.
*
* This linter uses [[https://github.com/less/less.js | lessc]] to detect
* errors and potential problems in [[http://lesscss.org/ | LESS]] code.
*/
final class ArcanistLesscLinter extends ArcanistExternalLinter {
const LINT_RUNTIME_ERROR = 1;
const LINT_ARGUMENT_ERROR = 2;
const LINT_FILE_ERROR = 3;
const LINT_NAME_ERROR = 4;
const LINT_OPERATION_ERROR = 5;
const LINT_PARSE_ERROR = 6;
const LINT_SYNTAX_ERROR = 7;
private $strictMath = false;
private $strictUnits = false;
public function getInfoName() {
return 'Less';
}
public function getInfoURI() {
return 'https://lesscss.org/';
}
public function getInfoDescription() {
return pht(
'Use the `%s` mode provided by `%s` to detect errors in '.
'Less source files.',
'--lint',
'lessc');
}
public function getLinterName() {
return 'LESSC';
}
public function getLinterConfigurationName() {
return 'lessc';
}
public function getLinterConfigurationOptions() {
return parent::getLinterConfigurationOptions() + array(
'lessc.strict-math' => array(
'type' => 'optional bool',
'help' => pht(
'Enable strict math, which only processes mathematical expressions '.
'inside extraneous parentheses.'),
),
'lessc.strict-units' => array(
'type' => 'optional bool',
'help' => pht('Enable strict handling of units in expressions.'),
),
);
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'lessc.strict-math':
$this->strictMath = $value;
return;
case 'lessc.strict-units':
$this->strictUnits = $value;
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
public function getLintNameMap() {
return array(
self::LINT_RUNTIME_ERROR => pht('Runtime Error'),
self::LINT_ARGUMENT_ERROR => pht('Argument Error'),
self::LINT_FILE_ERROR => pht('File Error'),
self::LINT_NAME_ERROR => pht('Name Error'),
self::LINT_OPERATION_ERROR => pht('Operation Error'),
self::LINT_PARSE_ERROR => pht('Parse Error'),
self::LINT_SYNTAX_ERROR => pht('Syntax Error'),
);
}
public function getDefaultBinary() {
return 'lessc';
}
public function getVersion() {
list($stdout) = execx('%C --version', $this->getExecutableCommand());
$matches = array();
$regex = '/^lessc (?P<version>\d+\.\d+\.\d+)\b/';
if (preg_match($regex, $stdout, $matches)) {
$version = $matches['version'];
} else {
return false;
}
}
public function getInstallInstructions() {
return pht('Install lessc using `%s`.', 'npm install -g less');
}
protected function getMandatoryFlags() {
return array(
'--lint',
'--no-color',
'--strict-math='.($this->strictMath ? 'on' : 'off'),
'--strict-units='.($this->strictUnits ? 'on' : 'off'),
);
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
$lines = phutil_split_lines($stderr, false);
$messages = array();
foreach ($lines as $line) {
$matches = null;
$match = preg_match(
'/^(?P<name>\w+): (?P<description>.+) '.
'in (?P<path>.+|-) '.
'on line (?P<line>\d+), column (?P<column>\d+):$/',
$line,
$matches);
if ($match) {
switch ($matches['name']) {
case 'RuntimeError':
$code = self::LINT_RUNTIME_ERROR;
break;
case 'ArgumentError':
$code = self::LINT_ARGUMENT_ERROR;
break;
case 'FileError':
$code = self::LINT_FILE_ERROR;
break;
case 'NameError':
$code = self::LINT_NAME_ERROR;
break;
case 'OperationError':
$code = self::LINT_OPERATION_ERROR;
break;
case 'ParseError':
$code = self::LINT_PARSE_ERROR;
break;
case 'SyntaxError':
$code = self::LINT_SYNTAX_ERROR;
break;
default:
throw new RuntimeException(
pht(
'Unrecognized lint message code "%s".',
$code));
}
$code = $this->getLintCodeFromLinterConfigurationKey($matches['name']);
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setLine($matches['line']);
$message->setChar($matches['column']);
$message->setCode($this->getLintMessageFullCode($code));
$message->setSeverity($this->getLintMessageSeverity($code));
$message->setName($this->getLintMessageName($code));
$message->setDescription(ucfirst($matches['description']));
$messages[] = $message;
}
}
return $messages;
}
}