~ubuntu-branches/ubuntu/wily/phabricator/wily

« back to all changes in this revision

Viewing changes to src/lint/linter/ArcanistLesscLinter.php

  • Committer: Package Import Robot
  • Author(s): Richard Sellam
  • Date: 2014-11-01 23:20:06 UTC
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: package-import@ubuntu.com-20141101232006-mvlnp0cil67tsboe
Tags: upstream-0~git20141101/arcanist
Import upstream version 0~git20141101, component arcanist

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
<?php
 
2
 
 
3
/**
 
4
 * A linter for LESSCSS files.
 
5
 *
 
6
 * This linter uses [[https://github.com/less/less.js | lessc]] to detect
 
7
 * errors and potential problems in [[http://lesscss.org/ | LESS]] code.
 
8
 */
 
9
final class ArcanistLesscLinter extends ArcanistExternalLinter {
 
10
 
 
11
  const LINT_RUNTIME_ERROR   = 1;
 
12
  const LINT_ARGUMENT_ERROR  = 2;
 
13
  const LINT_FILE_ERROR      = 3;
 
14
  const LINT_NAME_ERROR      = 4;
 
15
  const LINT_OPERATION_ERROR = 5;
 
16
  const LINT_PARSE_ERROR     = 6;
 
17
  const LINT_SYNTAX_ERROR    = 7;
 
18
 
 
19
  private $strictMath = false;
 
20
  private $strictUnits = false;
 
21
 
 
22
  public function getInfoName() {
 
23
    return pht('Less');
 
24
  }
 
25
 
 
26
  public function getInfoURI() {
 
27
    return 'https://lesscss.org/';
 
28
  }
 
29
 
 
30
  public function getInfoDescription() {
 
31
    return pht(
 
32
      'Use the `--lint` mode provided by `lessc` to detect errors in Less '.
 
33
      'source files.');
 
34
  }
 
35
 
 
36
  public function getLinterName() {
 
37
    return 'LESSC';
 
38
  }
 
39
 
 
40
  public function getLinterConfigurationName() {
 
41
    return 'lessc';
 
42
  }
 
43
 
 
44
  public function getLinterConfigurationOptions() {
 
45
    return parent::getLinterConfigurationOptions() + array(
 
46
      'lessc.strict-math' => array(
 
47
        'type' => 'optional bool',
 
48
        'help' => pht(
 
49
          'Enable strict math, which only processes mathematical expressions '.
 
50
          'inside extraneous parentheses.'),
 
51
      ),
 
52
      'lessc.strict-units' => array(
 
53
        'type' => 'optional bool',
 
54
        'help' => pht('Enable strict handling of units in expressions.'),
 
55
      ),
 
56
    );
 
57
  }
 
58
 
 
59
  public function setLinterConfigurationValue($key, $value) {
 
60
    switch ($key) {
 
61
      case 'lessc.strict-math':
 
62
        $this->strictMath = $value;
 
63
        return;
 
64
      case 'lessc.strict-units':
 
65
        $this->strictUnits = $value;
 
66
        return;
 
67
    }
 
68
 
 
69
    return parent::setLinterConfigurationValue($key, $value);
 
70
  }
 
71
 
 
72
  public function getLintNameMap() {
 
73
    return array(
 
74
      self::LINT_RUNTIME_ERROR   => pht('Runtime Error'),
 
75
      self::LINT_ARGUMENT_ERROR  => pht('Argument Error'),
 
76
      self::LINT_FILE_ERROR      => pht('File Error'),
 
77
      self::LINT_NAME_ERROR      => pht('Name Error'),
 
78
      self::LINT_OPERATION_ERROR => pht('Operation Error'),
 
79
      self::LINT_PARSE_ERROR     => pht('Parse Error'),
 
80
      self::LINT_SYNTAX_ERROR    => pht('Syntax Error'),
 
81
    );
 
82
  }
 
83
 
 
84
  public function getDefaultBinary() {
 
85
    return 'lessc';
 
86
  }
 
87
 
 
88
  public function getVersion() {
 
89
    list($stdout) = execx('%C --version', $this->getExecutableCommand());
 
90
 
 
91
    $matches = array();
 
92
    $regex = '/^lessc (?P<version>\d+\.\d+\.\d+)\b/';
 
93
    if (preg_match($regex, $stdout, $matches)) {
 
94
      $version = $matches['version'];
 
95
    } else {
 
96
      return false;
 
97
    }
 
98
  }
 
99
 
 
100
  public function getInstallInstructions() {
 
101
    return pht('Install lessc using `npm install -g less`.');
 
102
  }
 
103
 
 
104
  public function shouldExpectCommandErrors() {
 
105
    return true;
 
106
  }
 
107
 
 
108
  public function supportsReadDataFromStdin() {
 
109
    // Technically `lessc` can read data from standard input however, when doing
 
110
    // so, relative imports cannot be resolved. Therefore, this functionality is
 
111
    // disabled.
 
112
    return false;
 
113
  }
 
114
 
 
115
  public function getReadDataFromStdinFilename() {
 
116
    return '-';
 
117
  }
 
118
 
 
119
  protected function getMandatoryFlags() {
 
120
    return array(
 
121
      '--lint',
 
122
      '--no-color',
 
123
      '--strict-math='.($this->strictMath ? 'on' : 'off'),
 
124
      '--strict-units='.($this->strictUnits ? 'on' : 'off'),
 
125
    );
 
126
  }
 
127
 
 
128
  protected function parseLinterOutput($path, $err, $stdout, $stderr) {
 
129
    $lines = phutil_split_lines($stderr, false);
 
130
 
 
131
    $messages = array();
 
132
    foreach ($lines as $line) {
 
133
      $matches = null;
 
134
      $match = preg_match(
 
135
        '/^(?P<name>\w+): (?P<description>.+) '.
 
136
        'in (?P<path>.+|-) '.
 
137
        'on line (?P<line>\d+), column (?P<column>\d+):$/',
 
138
        $line,
 
139
        $matches);
 
140
 
 
141
      if ($match) {
 
142
        switch ($matches['name']) {
 
143
          case 'RuntimeError':
 
144
            $code = self::LINT_RUNTIME_ERROR;
 
145
            break;
 
146
 
 
147
          case 'ArgumentError':
 
148
            $code = self::LINT_ARGUMENT_ERROR;
 
149
            break;
 
150
 
 
151
          case 'FileError':
 
152
            $code = self::LINT_FILE_ERROR;
 
153
            break;
 
154
 
 
155
          case 'NameError':
 
156
            $code = self::LINT_NAME_ERROR;
 
157
            break;
 
158
 
 
159
          case 'OperationError':
 
160
            $code = self::LINT_OPERATION_ERROR;
 
161
            break;
 
162
 
 
163
          case 'ParseError':
 
164
            $code = self::LINT_PARSE_ERROR;
 
165
            break;
 
166
 
 
167
          case 'SyntaxError':
 
168
            $code = self::LINT_SYNTAX_ERROR;
 
169
            break;
 
170
 
 
171
          default:
 
172
            throw new RuntimeException(pht(
 
173
              'Unrecognized lint message code "%s".',
 
174
              $code));
 
175
        }
 
176
 
 
177
        $code = $this->getLintCodeFromLinterConfigurationKey($matches['name']);
 
178
 
 
179
        $message = new ArcanistLintMessage();
 
180
        $message->setPath($path);
 
181
        $message->setLine($matches['line']);
 
182
        $message->setChar($matches['column']);
 
183
        $message->setCode($this->getLintMessageFullCode($code));
 
184
        $message->setSeverity($this->getLintMessageSeverity($code));
 
185
        $message->setName($this->getLintMessageName($code));
 
186
        $message->setDescription(ucfirst($matches['description']));
 
187
 
 
188
        $messages[] = $message;
 
189
      }
 
190
    }
 
191
 
 
192
    if ($err && !$messages) {
 
193
      return false;
 
194
    }
 
195
 
 
196
    return $messages;
 
197
  }
 
198
 
 
199
}