Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow _ prefix in symfony coding standard #199

Merged
merged 3 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion src/Rules/File/FileNameRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public function __construct(
private string $case = self::SNAKE_CASE,
private ?string $baseDirectory = null,
private array $ignoredSubDirectories = [],
private string $optionalPrefix = '',
) {
}

Expand All @@ -36,6 +37,7 @@ public function getConfiguration(): array
'case' => $this->case,
'baseDirectory' => $this->baseDirectory,
'ignoredSubDirectories' => $this->ignoredSubDirectories,
'optionalPrefix' => $this->optionalPrefix,
];
}

Expand All @@ -59,6 +61,12 @@ protected function process(int $tokenPosition, array $tokens): void
// in order to avoid conflict with some file extensions.
$fileName = explode('.', FileHelper::removeDot($fileName))[0];

$prefix = '';
if (str_starts_with($fileName, $this->optionalPrefix)) {
$prefix = $this->optionalPrefix;
$fileName = substr($fileName, \strlen($this->optionalPrefix));
}

$expected = match ($this->case) {
self::SNAKE_CASE => StringUtil::toSnakeCase($fileName),
self::CAMEL_CASE => StringUtil::toCamelCase($fileName),
Expand All @@ -68,7 +76,7 @@ protected function process(int $tokenPosition, array $tokens): void

if ($expected !== $fileName) {
$this->addFileError(
sprintf('The file name must use %s; expected %s.', $this->case, $expected),
sprintf('The file name must use %s; expected %s.', $this->case, $prefix.$expected),
$token,
);
}
Expand Down
3 changes: 2 additions & 1 deletion src/Standard/Symfony.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
*
* @see https://twig.symfony.com/doc/3.x/coding_standards.html
* @see https://symfony.com/doc/current/templates.html#template-naming
* @see https://symfony.com/doc/current/best_practices.html#templates
*/
final class Symfony implements StandardInterface
{
public function getRules(): array
{
return [
...(new Twig())->getRules(),
new FileNameRule(baseDirectory: 'templates', ignoredSubDirectories: ['bundles']),
new FileNameRule(baseDirectory: 'templates', ignoredSubDirectories: ['bundles'], optionalPrefix: '_'),
new DirectoryNameRule(baseDirectory: 'templates', ignoredSubDirectories: ['bundles']),
new FileExtensionRule(),
];
Expand Down
27 changes: 16 additions & 11 deletions tests/Rules/AbstractRuleTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,25 +55,30 @@ protected function checkRule(
}
}

$messages = $report->getFileViolations($filePath);
$violations = $report->getFileViolations($filePath);

/** @var array<string|null> $messageIds */
$messageIds = [];
foreach ($messages as $message) {
if (Violation::LEVEL_FATAL === $message->getLevel()) {
$errorMessage = $message->getMessage();
$line = $message->getLine();
/** @var array<string, string> $messages */
$messages = [];
foreach ($violations as $violation) {
$message = $violation->getMessage();
if (Violation::LEVEL_FATAL === $violation->getLevel()) {
$line = $violation->getLine();

if (null !== $line) {
$errorMessage = sprintf('Line %s: %s', $line, $errorMessage);
$message = sprintf('Line %s: %s', $line, $message);
}
static::fail($errorMessage);
static::fail($message);
}

$messageIds[] = $message->getIdentifier()?->toString();
$id = $violation->getIdentifier()?->toString() ?? '';
if (isset($messages[$id])) {
static::fail(sprintf('Two violations have the same identifier "%s".', $id));
}

$messages[$id] = $message;
}

static::assertSame($expects, $messageIds);
static::assertSame($expects, $messages);
}

private function generateFilePath(): string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ final class BlockNameSpacingRuleTest extends AbstractRuleTestCase
public function testRule(): void
{
$this->checkRule(new BlockNameSpacingRule(), [
'BlockNameSpacing.After:1:5',
'BlockNameSpacing.Before:1:5',
'BlockNameSpacing.After:3:3',
'BlockNameSpacing.Before:3:3',
'BlockNameSpacing.After:1:5' => 'Expecting 1 whitespace after "extends"; found 0',
'BlockNameSpacing.Before:1:5' => 'Expecting 1 whitespace before "extends"; found 2',
'BlockNameSpacing.After:3:3' => 'Expecting 1 whitespace after "if"; found 4',
'BlockNameSpacing.Before:3:3' => 'Expecting 1 whitespace before "if"; found 0',
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ final class DelimiterSpacingRuleTest extends AbstractRuleTestCase
public function testRule(): void
{
$this->checkRule(new DelimiterSpacingRule(), [
'DelimiterSpacing.After:15:1',
'DelimiterSpacing.Before:15:12',
'DelimiterSpacing.After:15:15',
'DelimiterSpacing.Before:15:25',
'DelimiterSpacing.After:15:1' => 'Expecting 1 whitespace after "{%-"; found 0',
'DelimiterSpacing.Before:15:12' => 'Expecting 1 whitespace before "-%}"; found 2',
'DelimiterSpacing.After:15:15' => 'Expecting 1 whitespace after "{%-"; found 2',
'DelimiterSpacing.Before:15:25' => 'Expecting 1 whitespace before "-%}"; found 0',
]);
}
}
8 changes: 6 additions & 2 deletions tests/Rules/File/DirectoryName/DirectoryNameRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ public function testRuleInvalidTemplatesDirectory(): void
{
$this->checkRule(
new DirectoryNameRule(baseDirectory: __DIR__.'/templates'),
['DirectoryName.Error'],
[
'DirectoryName.Error' => 'The directory name must use snake_case; expected directory_name_rule_test.',
],
__DIR__.'/templates/directoryNameRuleTest/DirectoryNameRuleTest.twig'
);
}
Expand All @@ -64,7 +66,9 @@ public function testRulePascalCase(): void

public function testRuleInvalidDirectory(): void
{
$this->checkRule(new DirectoryNameRule(baseDirectory: __DIR__.'/..'), ['DirectoryName.Error']);
$this->checkRule(new DirectoryNameRule(baseDirectory: __DIR__.'/..'), [
'DirectoryName.Error' => 'The directory name must use snake_case; expected directory_name.',
]);
}

public function testRuleKebabCase(): void
Expand Down
8 changes: 6 additions & 2 deletions tests/Rules/File/FileExtension/FileExtensionRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ final class FileExtensionRuleTest extends AbstractRuleTestCase
{
public function testRule(): void
{
$this->checkRule(new FileExtensionRule(), ['FileExtension.Error']);
$this->checkRule(new FileExtensionRule(), [
'FileExtension.Error' => 'The file must use two extensions; found ".twig".',
]);
}

public function testRuleIgnoredFile(): void
Expand All @@ -26,7 +28,9 @@ public function testRuleValidFile(): void

public function testRuleInvalidDotFile(): void
{
$this->checkRule(new FileExtensionRule(), ['FileExtension.Error'], __DIR__.'/.dotfile.twig');
$this->checkRule(new FileExtensionRule(), [
'FileExtension.Error' => 'The file must use two extensions; found ".twig".',
], __DIR__.'/.dotfile.twig');
}

public function testRuleValidDotFileWithFormatExtension(): void
Expand Down
24 changes: 20 additions & 4 deletions tests/Rules/File/FileName/FileNameRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public function testConfiguration(): void
'case' => FileNameRule::SNAKE_CASE,
'baseDirectory' => null,
'ignoredSubDirectories' => [],
'optionalPrefix' => '',
],
(new FileNameRule())->getConfiguration()
);
Expand All @@ -25,26 +26,28 @@ public function testConfiguration(): void
'case' => FileNameRule::PASCAL_CASE,
'baseDirectory' => 'foo',
'ignoredSubDirectories' => ['bar'],
'optionalPrefix' => '_',
],
(new FileNameRule(
FileNameRule::PASCAL_CASE,
'foo',
['bar']
['bar'],
'_'
))->getConfiguration()
);
}

public function testRule(): void
{
$this->checkRule(new FileNameRule(), [
'FileName.Error',
'FileName.Error' => 'The file name must use snake_case; expected file_name_rule_test.',
]);
}

public function testRuleDotfile(): void
{
$this->checkRule(new FileNameRule(), [
'FileName.Error',
'FileName.Error' => 'The file name must use snake_case; expected file_name_rule_test.',
], __DIR__.'/.FileNameRuleTest.twig');
}

Expand Down Expand Up @@ -81,12 +84,25 @@ public function testRuleValidFileWithDot(): void
public function testRuleBaseDir(): void
{
$this->checkRule(new FileNameRule(baseDirectory: __DIR__.'/..'), [
'FileName.Error',
'FileName.Error' => 'The file name must use snake_case; expected file_name_rule_test.',
]);
}

public function testRuleIgnoredPath(): void
{
$this->checkRule(new FileNameRule(baseDirectory: __DIR__.'/..', ignoredSubDirectories: ['FileName']), []);
}

public function testRuleOptionalPrefix(): void
{
$this->checkRule(new FileNameRule(), [
'FileName.Error' => 'The file name must use snake_case; expected file_name_rule_test.',
], __DIR__.'/_file_name_rule_test.twig');

$this->checkRule(new FileNameRule(optionalPrefix: '_'), [], __DIR__.'/_file_name_rule_test.twig');

$this->checkRule(new FileNameRule(FileNameRule::CAMEL_CASE, optionalPrefix: '_'), [
'FileName.Error' => 'The file name must use camelCase; expected _fileNameRuleTest.',
], __DIR__.'/_file_name_rule_test.twig');
}
}
1 change: 1 addition & 0 deletions tests/Rules/File/FileName/_file_name_rule_test.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Nothing
32 changes: 16 additions & 16 deletions tests/Rules/Function/IncludeFunction/IncludeFunctionRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,22 @@ public function testRule(): void
new PunctuationSpacingRule(),
],
[
'IncludeFunction.Error:1:4',
'IncludeFunction.Error:2:4',
'IncludeFunction.Error:3:4',
'IncludeFunction.Error:4:4',
'IncludeFunction.Error:5:4',
'IncludeFunction.Error:6:4',
'IncludeFunction.Error:7:4',
'IncludeFunction.Error:8:4',
'IncludeFunction.Error:9:4',
'IncludeFunction.Error:10:4',
'IncludeFunction.Error:11:4',
'IncludeFunction.Error:12:4',
'IncludeFunction.Error:13:4',
'IncludeFunction.Error:14:4',
'IncludeFunction.Error:15:5',
'IncludeFunction.Error:16:5',
'IncludeFunction.Error:1:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:2:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:3:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:4:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:5:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:6:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:7:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:8:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:9:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:10:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:11:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:12:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:13:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:14:4' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:15:5' => 'Include function must be used instead of include tag.',
'IncludeFunction.Error:16:5' => 'Include function must be used instead of include tag.',
]
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ final class OperatorNameSpacingRuleTest extends AbstractRuleTestCase
public function testRule(): void
{
$this->checkRule(new OperatorNameSpacingRule(), [
'OperatorNameSpacing.Error:2:13',
'OperatorNameSpacing.Error:3:13',
'OperatorNameSpacing.Error:4:10',
'OperatorNameSpacing.Error:2:13' => 'A single line operator should not have consecutive spaces.',
'OperatorNameSpacing.Error:3:13' => 'A single line operator should not have consecutive spaces.',
'OperatorNameSpacing.Error:4:10' => 'A single line operator should not have consecutive spaces.',
]);
}
}
88 changes: 44 additions & 44 deletions tests/Rules/Operator/OperatorSpacing/OperatorSpacingRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,50 +12,50 @@ final class OperatorSpacingRuleTest extends AbstractRuleTestCase
public function testRule(): void
{
$this->checkRule(new OperatorSpacingRule(), [
'OperatorSpacing.After:1:5',
'OperatorSpacing.Before:1:5',
'OperatorSpacing.After:2:5',
'OperatorSpacing.Before:2:5',
'OperatorSpacing.After:3:5',
'OperatorSpacing.Before:3:5',
'OperatorSpacing.After:4:5',
'OperatorSpacing.Before:4:5',
'OperatorSpacing.After:5:5',
'OperatorSpacing.Before:5:5',
'OperatorSpacing.After:6:5',
'OperatorSpacing.Before:6:5',
'OperatorSpacing.After:7:5',
'OperatorSpacing.Before:7:5',
'OperatorSpacing.After:8:7',
'OperatorSpacing.Before:8:7',
'OperatorSpacing.After:9:10',
'OperatorSpacing.Before:9:10',
'OperatorSpacing.After:9:19',
'OperatorSpacing.Before:9:19',
'OperatorSpacing.After:10:5',
'OperatorSpacing.Before:10:5',
'OperatorSpacing.After:11:4',
'OperatorSpacing.After:12:11',
'OperatorSpacing.Before:12:11',
'OperatorSpacing.After:13:11',
'OperatorSpacing.Before:13:11',
'OperatorSpacing.After:14:7',
'OperatorSpacing.Before:14:7',
'OperatorSpacing.After:15:7',
'OperatorSpacing.Before:15:7',
'OperatorSpacing.After:19:5',
'OperatorSpacing.Before:19:5',
'OperatorSpacing.After:20:5',
'OperatorSpacing.Before:20:5',
'OperatorSpacing.After:22:6',
'OperatorSpacing.After:33:10',
'OperatorSpacing.Before:33:10',
'OperatorSpacing.After:35:13',
'OperatorSpacing.Before:35:13',
'OperatorSpacing.After:36:13',
'OperatorSpacing.Before:36:13',
'OperatorSpacing.After:37:13',
'OperatorSpacing.Before:37:13',
'OperatorSpacing.After:1:5' => 'Expecting 1 whitespace after "+"; found 0',
'OperatorSpacing.Before:1:5' => 'Expecting 1 whitespace before "+"; found 0',
'OperatorSpacing.After:2:5' => 'Expecting 1 whitespace after "-"; found 0',
'OperatorSpacing.Before:2:5' => 'Expecting 1 whitespace before "-"; found 0',
'OperatorSpacing.After:3:5' => 'Expecting 1 whitespace after "/"; found 0',
'OperatorSpacing.Before:3:5' => 'Expecting 1 whitespace before "/"; found 0',
'OperatorSpacing.After:4:5' => 'Expecting 1 whitespace after "*"; found 0',
'OperatorSpacing.Before:4:5' => 'Expecting 1 whitespace before "*"; found 0',
'OperatorSpacing.After:5:5' => 'Expecting 1 whitespace after "%"; found 0',
'OperatorSpacing.Before:5:5' => 'Expecting 1 whitespace before "%"; found 0',
'OperatorSpacing.After:6:5' => 'Expecting 1 whitespace after "//"; found 0',
'OperatorSpacing.Before:6:5' => 'Expecting 1 whitespace before "//"; found 0',
'OperatorSpacing.After:7:5' => 'Expecting 1 whitespace after "**"; found 0',
'OperatorSpacing.Before:7:5' => 'Expecting 1 whitespace before "**"; found 0',
'OperatorSpacing.After:8:7' => 'Expecting 1 whitespace after "~"; found 0',
'OperatorSpacing.Before:8:7' => 'Expecting 1 whitespace before "~"; found 0',
'OperatorSpacing.After:9:10' => 'Expecting 1 whitespace after "?"; found 2',
'OperatorSpacing.Before:9:10' => 'Expecting 1 whitespace before "?"; found 2',
'OperatorSpacing.After:9:19' => 'Expecting 1 whitespace after ":"; found 2',
'OperatorSpacing.Before:9:19' => 'Expecting 1 whitespace before ":"; found 2',
'OperatorSpacing.After:10:5' => 'Expecting 1 whitespace after "=="; found 0',
'OperatorSpacing.Before:10:5' => 'Expecting 1 whitespace before "=="; found 0',
'OperatorSpacing.After:11:4' => 'Expecting 1 whitespace after "not"; found 3',
'OperatorSpacing.After:12:11' => 'Expecting 1 whitespace after "and"; found 3',
'OperatorSpacing.Before:12:11' => 'Expecting 1 whitespace before "and"; found 2',
'OperatorSpacing.After:13:11' => 'Expecting 1 whitespace after "or"; found 3',
'OperatorSpacing.Before:13:11' => 'Expecting 1 whitespace before "or"; found 2',
'OperatorSpacing.After:14:7' => 'Expecting 1 whitespace after "in"; found 3',
'OperatorSpacing.Before:14:7' => 'Expecting 1 whitespace before "in"; found 2',
'OperatorSpacing.After:15:7' => 'Expecting 1 whitespace after "is"; found 3',
'OperatorSpacing.Before:15:7' => 'Expecting 1 whitespace before "is"; found 2',
'OperatorSpacing.After:19:5' => 'Expecting 1 whitespace after "?:"; found 0',
'OperatorSpacing.Before:19:5' => 'Expecting 1 whitespace before "?:"; found 0',
'OperatorSpacing.After:20:5' => 'Expecting 1 whitespace after "??"; found 0',
'OperatorSpacing.Before:20:5' => 'Expecting 1 whitespace before "??"; found 0',
'OperatorSpacing.After:22:6' => 'Expecting 1 whitespace after "+"; found 0',
'OperatorSpacing.After:33:10' => 'Expecting 1 whitespace after "+"; found 0',
'OperatorSpacing.Before:33:10' => 'Expecting 1 whitespace before "+"; found 0',
'OperatorSpacing.After:35:13' => 'Expecting 1 whitespace after "starts with"; found 2',
'OperatorSpacing.Before:35:13' => 'Expecting 1 whitespace before "starts with"; found 2',
'OperatorSpacing.After:36:13' => 'Expecting 1 whitespace after "ends with"; found 2',
'OperatorSpacing.Before:36:13' => 'Expecting 1 whitespace before "ends with"; found 2',
'OperatorSpacing.After:37:13' => 'Expecting 1 whitespace after "matches"; found 2',
'OperatorSpacing.Before:37:13' => 'Expecting 1 whitespace before "matches"; found 2',
]);
}

Expand Down
Loading
Loading