src/lint/linter/PrettierLinter.php (89 lines of code) (raw):
<?php
/**
* Copyright 2018 Pinterest, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Lints JavaScript and JSX files using Prettier
*/
final class PrettierLinter extends ArcanistExternalLinter {
private $cwd = '';
public function getInfoName() {
return 'Prettier';
}
public function getInfoURI() {
return 'https://prettier.io/';
}
public function getInfoDescription() {
return pht('An opinionated code formatter with canonicalized AST-derived output');
}
public function getLinterName() {
return 'PRETTIER';
}
public function getLinterConfigurationName() {
return 'prettier';
}
public function getDefaultBinary() {
if ($this->cwd) {
$realCWD = Filesystem::resolvePath($this->cwd, $this->getProjectRoot());
list($err, $stdout, $stderr) = exec_manual('yarn -s --cwd %s bin prettier', $realCWD);
if ($stdout) {
return strtok($stdout, "\n");
}
} else {
$localBinaryPath = Filesystem::resolvePath('./node_modules/.bin/prettier');
if (Filesystem::binaryExists($localBinaryPath)) {
return $localBinaryPath;
}
}
// Fallback on global install & fallthrough to internal existence checks
return 'prettier';
}
public function getVersion() {
list($err, $stdout, $stderr) = exec_manual('%C -v', $this->getExecutableCommand());
return $stdout;
}
public function getLinterConfigurationOptions() {
$options = array(
'prettier.cwd' => array(
'type' => 'optional string',
'help' => pht('Specify a project sub-directory for both the local prettier install and the sub-directory to lint within.'),
),
);
return $options + parent::getLinterConfigurationOptions();
}
public function setLinterConfigurationValue($key, $value) {
switch ($key) {
case 'prettier.cwd':
$this->cwd = $value;
return;
}
return parent::setLinterConfigurationValue($key, $value);
}
public function getInstallInstructions() {
return pht(
"\n\t%s[%s globally] run: `%s`\n\t[%s locally] run either: `%s` OR `%s`",
$this->cwd ? pht("[%s globally] (required for %s) run: `%s`\n\t",
'yarn',
'--cwd',
'npm install --global yarn@1') : '',
'prettier',
'npm install --global prettier',
'prettier',
'npm install --save-dev prettier',
'yarn add --dev prettier'
);
}
protected function parseLinterOutput($path, $err, $stdout, $stderr) {
if ($err) {
return false;
}
if ($this->getData($path) == $stdout) {
return array();
}
$message = new ArcanistLintMessage();
$message->setPath($path);
$message->setSeverity(ArcanistLintSeverity::SEVERITY_AUTOFIX);
$message->setName('Prettier Format');
$message->setLine(1);
$message->setCode($this->getLinterName());
$message->setChar(1);
$message->setDescription('This file has not been prettier-ified');
$message->setOriginalText($this->getData($path));
$message->setReplacementText($stdout);
$messages[] = $message;
return $messages;
}
}