Skip to content
Snippets Groups Projects
Commit 6b713cc4 authored by Jan-Hendrik Willms's avatar Jan-Hendrik Willms
Browse files

initial commit

parent 03d4030b
No related branches found
No related tags found
No related merge requests found
<?php
final class JSLinter implements LinterType
{
private function getLinterFilepath(): string
{
return getcwd() . '/node_modules/.bin/eslint';
}
public function getType(): string
{
return 'js';
}
public function isAailable(): bool
{
$linter_filepath = $this->getLinterFilepath();
return file_exists($linter_filepath)
&& is_executable($linter_filepath);
}
public function isFileValid(string $filename): bool
{
return fnmatch('resources/**/*.js', $filename);
}
public function lintCommand(string $filename): string
{
return "{$this->getLinterFilepath()} --format json {$filename} 2>&1";
}
public function analyze(?string $result): ?array
{
if (!$result) {
return null;
}
$json = json_decode($result, true);
return array_map(function ($message) {
$error = "Line {$message['line']}:{$message['column']} - {$message['message']}";
if ($message['fatal']) {
$error = 'Fatal error: ' . $error;
}
return $error;
}, $json[0]['messages']);
}
}
<?php
final class LESSLinter implements LinterType
{
private function getLinterFilepath(): string
{
return getcwd() . '/node_modules/.bin/lessc';
}
public function getType(): string
{
return 'less & css';
}
public function isAailable(): bool
{
$linter_filepath = $this->getLinterFilepath();
return file_exists($linter_filepath)
&& is_executable($linter_filepath);
}
public function isFileValid(string $filename): bool
{
return fnmatch('resources/**/*.css', $filename)
?: fnmatch('resources/**/*.less', $filename);
}
public function lintCommand(string $filename): string
{
return "{$this->getLinterFilepath()} --lint {$filename} 2>&1";
}
public function analyze(?string $result): ?array
{
if (!$result) {
return null;
}
$result = removeAnsi($result);
$lines = explode("\n", $result);
$lines = array_filter($lines);
return $lines;
}
}
<?php
final class Linter
{
/**
* @var array<LinterType>
*/
private $linters = [];
/**
* @var array<string>
*/
private $files = [];
public function addLinter(LinterType $linter)
{
if ($linter->isAailable()) {
$this->linters[$linter->getType()] = $linter;
}
}
public function addFile(string $filename): bool
{
foreach ($this->linters as $linter) {
if (!$linter->isFileValid($filename)) {
continue;
}
if (!isset($this->files[$linter->getType()])) {
$this->files[$linter->getType()] = [];
}
$this->files[$linter->getType()][] = $filename;
return true;
}
return false;
}
public function addFiles(array $filenames): int
{
$added = 0;
foreach ($filenames as $filename) {
if ($this->addFile($filename)) {
$added += 1;
}
}
return $added;
}
public function lint(): bool
{
$failed = 0;
foreach ($this->files as $type => $files) {
$linter = $this->linters[$type];
echo "Syntax checking {$type} files...\n";
foreach ($files as $filename) {
$command = $linter->lintCommand($filename);
$linter_result = shell_exec($command);
$result = $linter->analyze($linter_result);
if ($result !== null && is_array($result)) {
$failed += 1;
echo "- Error detected in {$filename}\n";
foreach ($result as $line) {
echo "\t{$line}\n";
}
}
}
}
return $failed === 0;
}
}
<?php
interface LinterType
{
public function getType(): string;
public function isAailable(): bool;
public function isFileValid(string $filename): bool;
public function lintCommand(string $filename): string;
public function analyze(?string $result): ?array;
}
<?php
final class PHPLinter implements LinterType
{
public function getType(): string
{
return 'php';
}
public function isAailable(): bool
{
return (bool) `which php`;
}
public function isFileValid(string $filename): bool
{
return fnmatch('*.php', $filename);
}
public function lintCommand(string $filename): string
{
return "php -l {$filename} 2>&1";
}
public function analyze(?string $result): ?array
{
if (strpos($result, 'No syntax errors detected') !== false) {
return null;
}
$lines = explode("\n", $result);
$lines = array_filter($lines);
$lines = array_slice($lines, 1, -1);
return $lines;
}
}
<?php
spl_autoload_register(function ($class) {
$class_name = __DIR__ . '/' . $class . '.php';
if (file_exists($class_name)) {
require $class_name;
}
});
function removeAnsi(string $input): string {
return preg_replace('#\\x1b[[][^A-Za-z]*[A-Za-z]#', '', $input);
}
#!/usr/bin/env php
<?php
require __DIR__ . '/lib/bootstrap.php';
$linter = new Linter();
$linter->addLinter(new PHPLinter());
$linter->addLinter(new JSLinter());
$linter->addLinter(new LESSLinter());
$files = explode("\n", stream_get_contents(STDIN));
$files = array_filter($files);
$linter->addFiles($files);
$exitCode = $linter->lint() ? 0 : 2;
if ($exitCode === 0) {
echo "✔️ No errors detected\n";
}
exit($exitCode);
git stash -q --keep-index
git status --porcelain | grep --color=never '^[AM]' | cut -c4- | .git/hooks/linter.php
RESULT=$?
git stash pop -q
[ $RESULT -ne 0 ] && exit 1
exit 0
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment