clean install

This commit is contained in:
2024-12-10 15:08:16 +01:00
commit e14eb2d8fd
31193 changed files with 3555714 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
<?php declare(strict_types = 1);
namespace SlevomatCodingStandard\Sniffs\Files;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use SlevomatCodingStandard\Helpers\FunctionHelper;
use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
use function array_filter;
use function array_keys;
use function array_reduce;
use function sprintf;
use const T_OPEN_TAG;
class FileLengthSniff implements Sniff
{
public const CODE_FILE_TOO_LONG = 'FileTooLong';
/** @var int */
public $maxLinesLength = 250;
/** @var bool */
public $includeComments = false;
/** @var bool */
public $includeWhitespace = false;
/**
* @return array<int, (int|string)>
*/
public function register(): array
{
return [T_OPEN_TAG];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): void
{
$this->maxLinesLength = SniffSettingsHelper::normalizeInteger($this->maxLinesLength);
$flags = array_keys(array_filter([
FunctionHelper::LINE_INCLUDE_COMMENT => $this->includeComments,
FunctionHelper::LINE_INCLUDE_WHITESPACE => $this->includeWhitespace,
]));
$flags = array_reduce($flags, static function ($carry, $flag): int {
return $carry | $flag;
}, 0);
$length = FunctionHelper::getLineCount($phpcsFile, $pointer, $flags);
if ($length <= $this->maxLinesLength) {
return;
}
$errorMessage = sprintf('Your file is too long. Currently using %d lines. Can be up to %d lines.', $length, $this->maxLinesLength);
$phpcsFile->addError($errorMessage, $pointer, self::CODE_FILE_TOO_LONG);
}
}

View File

@@ -0,0 +1,88 @@
<?php declare(strict_types = 1);
namespace SlevomatCodingStandard\Sniffs\Files;
use SlevomatCodingStandard\Helpers\StringHelper;
use function array_fill_keys;
use function array_filter;
use function array_map;
use function array_shift;
use function array_unshift;
use function count;
use function explode;
use function implode;
use function in_array;
use function pathinfo;
use function preg_split;
use function strlen;
use function strtolower;
use function substr;
use const PATHINFO_EXTENSION;
class FilepathNamespaceExtractor
{
/** @var array<string, string> */
private $rootNamespaces;
/** @var array<string, bool> dir(string) => true(bool) */
private $skipDirs;
/** @var list<string> */
private $extensions;
/**
* @param array<string, string> $rootNamespaces directory(string) => namespace
* @param list<string> $skipDirs
* @param list<string> $extensions index(integer) => extension
*/
public function __construct(array $rootNamespaces, array $skipDirs, array $extensions)
{
$this->rootNamespaces = $rootNamespaces;
$this->skipDirs = array_fill_keys($skipDirs, true);
$this->extensions = array_map(static function (string $extension): string {
return strtolower($extension);
}, $extensions);
}
public function getTypeNameFromProjectPath(string $path): ?string
{
$extension = strtolower(pathinfo($path, PATHINFO_EXTENSION));
if (!in_array($extension, $this->extensions, true)) {
return null;
}
/** @var list<string> $pathParts */
$pathParts = preg_split('~[/\\\]~', $path);
$rootNamespace = null;
while (count($pathParts) > 0) {
array_shift($pathParts);
foreach ($this->rootNamespaces as $directory => $namespace) {
if (!StringHelper::startsWith(implode('/', $pathParts) . '/', $directory . '/')) {
continue;
}
$directoryPartsCount = count(explode('/', $directory));
for ($i = 0; $i < $directoryPartsCount; $i++) {
array_shift($pathParts);
}
$rootNamespace = $namespace;
break 2;
}
}
if ($rootNamespace === null) {
return null;
}
array_unshift($pathParts, $rootNamespace);
$typeName = implode('\\', array_filter($pathParts, function (string $pathPart): bool {
return !isset($this->skipDirs[$pathPart]);
}));
return substr($typeName, 0, -strlen('.' . $extension));
}
}

View File

@@ -0,0 +1,138 @@
<?php declare(strict_types = 1);
namespace SlevomatCodingStandard\Sniffs\Files;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use SlevomatCodingStandard\Helpers\UseStatementHelper;
use function in_array;
use function is_int;
use function ltrim;
use function sprintf;
use function strlen;
use function strrpos;
use const T_COMMENT;
use const T_DOC_COMMENT_STRING;
use const T_OPEN_TAG;
class LineLengthSniff implements Sniff
{
public const CODE_LINE_TOO_LONG = 'LineTooLong';
/**
* The limit that the length of a line must not exceed.
*
* @var int
*/
public $lineLengthLimit = 120;
/**
* Whether or not to ignore comment lines.
*
* @var bool
*/
public $ignoreComments = false;
/**
* Whether or not to ignore import lines (use).
*
* @var bool
*/
public $ignoreImports = true;
/**
* @return array<int, (int|string)>
*/
public function register(): array
{
return [T_OPEN_TAG];
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @phpcsSuppress SlevomatCodingStandard.Functions.UnusedParameter.UnusedParameter
* @param int $pointer
*/
public function process(File $phpcsFile, $pointer): int
{
$tokens = $phpcsFile->getTokens();
for ($i = 0; $i < $phpcsFile->numTokens; $i++) {
if ($tokens[$i]['column'] !== 1) {
continue;
}
$this->checkLineLength($phpcsFile, $i);
}
return $phpcsFile->numTokens + 1;
}
private function checkLineLength(File $phpcsFile, int $pointer): void
{
$tokens = $phpcsFile->getTokens();
if ($tokens[$pointer]['column'] === 1 && $tokens[$pointer]['length'] === 0) {
// Blank line.
return;
}
$line = $tokens[$pointer]['line'];
$nextLineStartPtr = $pointer;
while (isset($tokens[$nextLineStartPtr]) && $line === $tokens[$nextLineStartPtr]['line']) {
$pointer = $nextLineStartPtr;
$nextLineStartPtr++;
}
if ($tokens[$pointer]['content'] === $phpcsFile->eolChar) {
$pointer--;
}
$lineLength = $tokens[$pointer]['column'] + $tokens[$pointer]['length'] - 1;
if ($lineLength <= $this->lineLengthLimit) {
return;
}
if (in_array($tokens[$pointer]['code'], [T_COMMENT, T_DOC_COMMENT_STRING], true)) {
if ($this->ignoreComments === true) {
return;
}
// If this is a long comment, check if it can be broken up onto multiple lines.
// Some comments contain unbreakable strings like URLs and so it makes sense
// to ignore the line length in these cases if the URL would be longer than the max
// line length once you indent it to the correct level.
if ($lineLength > $this->lineLengthLimit) {
$oldLength = strlen($tokens[$pointer]['content']);
$newLength = strlen(ltrim($tokens[$pointer]['content'], "/#\t "));
$indent = $tokens[$pointer]['column'] - 1 + $oldLength - $newLength;
$nonBreakingLength = $tokens[$pointer]['length'];
$space = strrpos($tokens[$pointer]['content'], ' ');
if ($space !== false) {
$nonBreakingLength -= $space + 1;
}
if ($nonBreakingLength + $indent > $this->lineLengthLimit) {
return;
}
}
}
if ($this->ignoreImports) {
$usePointer = UseStatementHelper::getUseStatementPointer($phpcsFile, $pointer - 1);
if (
is_int($usePointer)
&& $tokens[$usePointer]['line'] === $tokens[$pointer]['line']
&& UseStatementHelper::isImportUse($phpcsFile, $usePointer)
) {
return;
}
}
$error = sprintf('Line exceeds maximum limit of %s characters, contains %s characters.', $this->lineLengthLimit, $lineLength);
$phpcsFile->addError($error, $pointer, self::CODE_LINE_TOO_LONG);
}
}

View File

@@ -0,0 +1,188 @@
<?php declare(strict_types = 1);
namespace SlevomatCodingStandard\Sniffs\Files;
use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use SlevomatCodingStandard\Helpers\ClassHelper;
use SlevomatCodingStandard\Helpers\NamespaceHelper;
use SlevomatCodingStandard\Helpers\SniffSettingsHelper;
use SlevomatCodingStandard\Helpers\StringHelper;
use SlevomatCodingStandard\Helpers\TokenHelper;
use function count;
use function explode;
use function min;
use function sprintf;
use function str_replace;
use function strcasecmp;
use function strlen;
use function substr;
use function ucfirst;
use function uksort;
use const DIRECTORY_SEPARATOR;
use const T_STRING;
class TypeNameMatchesFileNameSniff implements Sniff
{
public const CODE_NO_MATCH_BETWEEN_TYPE_NAME_AND_FILE_NAME = 'NoMatchBetweenTypeNameAndFileName';
/** @var array<string, string> */
public $rootNamespaces = [];
/** @var list<string> */
public $skipDirs = [];
/** @var list<string> */
public $ignoredNamespaces = [];
/** @var list<string> */
public $extensions = ['php'];
/** @var array<string, string>|null */
private $normalizedRootNamespaces;
/** @var list<string>|null */
private $normalizedSkipDirs;
/** @var list<string>|null */
private $normalizedIgnoredNamespaces;
/** @var list<string>|null */
private $normalizedExtensions;
/** @var FilepathNamespaceExtractor */
private $namespaceExtractor;
/**
* @return array<int, (int|string)>
*/
public function register(): array
{
return TokenHelper::$typeKeywordTokenCodes;
}
/**
* @phpcsSuppress SlevomatCodingStandard.TypeHints.ParameterTypeHint.MissingNativeTypeHint
* @param int $typePointer
*/
public function process(File $phpcsFile, $typePointer): void
{
$tokens = $phpcsFile->getTokens();
/** @var int $namePointer */
$namePointer = TokenHelper::findNext($phpcsFile, T_STRING, $typePointer + 1);
$typeName = NamespaceHelper::normalizeToCanonicalName(ClassHelper::getFullyQualifiedName($phpcsFile, $typePointer));
foreach ($this->getIgnoredNamespaces() as $ignoredNamespace) {
if (!StringHelper::startsWith($typeName, $ignoredNamespace . '\\')) {
continue;
}
return;
}
$filename = str_replace('/', DIRECTORY_SEPARATOR, $phpcsFile->getFilename());
$basePath = str_replace('/', DIRECTORY_SEPARATOR, $phpcsFile->config->basepath ?? '');
if ($basePath !== '' && StringHelper::startsWith($filename, $basePath)) {
$filename = substr($filename, strlen($basePath));
}
$expectedTypeName = $this->getNamespaceExtractor()->getTypeNameFromProjectPath($filename);
if ($typeName === $expectedTypeName) {
return;
}
$phpcsFile->addError(
sprintf(
'%s name %s does not match filepath %s.',
ucfirst($tokens[$typePointer]['content']),
$typeName,
$phpcsFile->getFilename()
),
$namePointer,
self::CODE_NO_MATCH_BETWEEN_TYPE_NAME_AND_FILE_NAME
);
}
/**
* @return array<string, string> path(string) => namespace
*/
private function getRootNamespaces(): array
{
if ($this->normalizedRootNamespaces === null) {
/** @var array<string, string> $normalizedRootNamespaces */
$normalizedRootNamespaces = SniffSettingsHelper::normalizeAssociativeArray($this->rootNamespaces);
$this->normalizedRootNamespaces = $normalizedRootNamespaces;
uksort($this->normalizedRootNamespaces, static function (string $a, string $b): int {
$aParts = explode('/', str_replace('\\', '/', $a));
$bParts = explode('/', str_replace('\\', '/', $b));
$minPartsCount = min(count($aParts), count($bParts));
for ($i = 0; $i < $minPartsCount; $i++) {
$comparison = strcasecmp($bParts[$i], $aParts[$i]);
if ($comparison === 0) {
continue;
}
return $comparison;
}
return count($bParts) <=> count($aParts);
});
}
return $this->normalizedRootNamespaces;
}
/**
* @return list<string>
*/
private function getSkipDirs(): array
{
if ($this->normalizedSkipDirs === null) {
$this->normalizedSkipDirs = SniffSettingsHelper::normalizeArray($this->skipDirs);
}
return $this->normalizedSkipDirs;
}
/**
* @return list<string>
*/
private function getIgnoredNamespaces(): array
{
if ($this->normalizedIgnoredNamespaces === null) {
$this->normalizedIgnoredNamespaces = SniffSettingsHelper::normalizeArray($this->ignoredNamespaces);
}
return $this->normalizedIgnoredNamespaces;
}
/**
* @return list<string>
*/
private function getExtensions(): array
{
if ($this->normalizedExtensions === null) {
$this->normalizedExtensions = SniffSettingsHelper::normalizeArray($this->extensions);
}
return $this->normalizedExtensions;
}
private function getNamespaceExtractor(): FilepathNamespaceExtractor
{
if ($this->namespaceExtractor === null) {
$this->namespaceExtractor = new FilepathNamespaceExtractor(
$this->getRootNamespaces(),
$this->getSkipDirs(),
$this->getExtensions()
);
}
return $this->namespaceExtractor;
}
}