Skip to content

Commit

Permalink
Merge pull request #81 from inpsyde/template-semicolon-sniff
Browse files Browse the repository at this point in the history
  • Loading branch information
shvlv committed Feb 26, 2024
2 parents 19229f9 + cd931e0 commit 29f8bc7
Show file tree
Hide file tree
Showing 34 changed files with 236 additions and 47 deletions.
109 changes: 109 additions & 0 deletions InpsydeTemplates/Sniffs/Formatting/TrailingSemicolonSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
<?php

/*
* This file is part of the "php-coding-standards" package.
*
* Copyright (c) 2023 Inpsyde GmbH
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

declare(strict_types=1);

namespace InpsydeTemplates\Sniffs\Formatting;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Sniffs\Sniff;
use PHP_CodeSniffer\Util\Tokens;

/**
* @psalm-type Token = array{
* type: string,
* code: string|int,
* line: int
* }
*/
final class TrailingSemicolonSniff implements Sniff
{
/**
* @return list<int|string>
*/
public function register(): array
{
return [
T_SEMICOLON,
];
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* phpcs:disable Inpsyde.CodeQuality.ArgumentTypeDeclaration
*/
public function process(File $phpcsFile, $stackPtr): void
{
// phpcs:enable Inpsyde.CodeQuality.ArgumentTypeDeclaration

/** @var array<int, Token> $tokens */
$tokens = $phpcsFile->getTokens();
$currentLine = $tokens[$stackPtr]['line'];

$nextNonEmptyPosition = $phpcsFile->findNext(
Tokens::$emptyTokens,
($stackPtr + 1),
null,
true
);

if (!is_int($nextNonEmptyPosition) || !isset($tokens[$nextNonEmptyPosition])) {
return;
}

$nextNonEmptyToken = $tokens[$nextNonEmptyPosition];

if ($nextNonEmptyToken['line'] !== $currentLine) {
return;
}

if ($nextNonEmptyToken['code'] !== T_CLOSE_TAG) {
return;
}

$message = sprintf('Trailing semicolon found in line %d.', $currentLine);

if ($phpcsFile->addFixableWarning($message, $stackPtr, 'Found')) {
$this->fix($stackPtr, $phpcsFile);
}
}

/**
* @param int $position
* @param File $file
*/
private function fix(int $position, File $file): void
{
$fixer = $file->fixer;
$fixer->beginChangeset();

$fixer->replaceToken($position, '');

$fixer->endChangeset();
}
}
10 changes: 10 additions & 0 deletions InpsydeTemplates/ruleset.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<ruleset name="Inpsyde PHP Templates Coding Standard">

<description>Coding standards for PHP templates.</description>

<rule ref="Inpsyde">
<exclude name="Inpsyde.CodeQuality.NoElse" />
</rule>

</ruleset>
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,40 @@ For **notes and configuration** see [`/inpsyde-custom-sniffs.md`](/inpsyde-custo

-------------

## Template Rules

The `InpsydeTemplates` ruleset extends the standard `Inpsyde` ruleset with some template-specific
sniffs while disabling some rules that are not useful in templating context.

The recommended way to use the `InpsydeTemplates` ruleset is as follows:

```xml
<ruleset>
<file>./src/</file>
<file>./tests</file>
<file>./templates</file>
<file>./views</file>

<rule ref="Inpsyde">
<exclude-pattern>*/templates/*</exclude-pattern>
<exclude-pattern>*/views/*</exclude-pattern>
</rule>

<rule ref="InpsydeTemplates">
<include-pattern>*/templates/*</include-pattern>
<include-pattern>*/views/*</include-pattern>
</rule>
</ruleset>
```
The following `Inpsyde` rules are disabled:
* `NoElse`

The following templates-specific rules are available:

| Sniff name | Description | Has Config | Auto-Fixable |
|:--------------------|:--------------------------------------------------|:----------:|:------------:|
| `TrailingSemicolon` | Remove trailing semicolon before closing PHP tag. | ||

# Removing or Disabling Rules

## Rules Tree
Expand Down
2 changes: 1 addition & 1 deletion tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
die('Please install via Composer before running tests.');
}

putenv("SNIFFS_PATH={$libDir}/Inpsyde/Sniffs");
putenv("LIB_PATH={$libDir}");
putenv('SNIFFS_NAMESPACE=Inpsyde\\Sniffs');
putenv("FIXTURES_PATH={$testsDir}/fixtures");

Expand Down
24 changes: 18 additions & 6 deletions tests/cases/FixturesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -209,24 +209,36 @@ private function createPhpcsForFixture(
array $properties
): File {

$sniffFile = str_replace('.', '/', "{$sniffName}Sniff");
$sniffPath = getenv('SNIFFS_PATH') . "/{$sniffFile}.php";
$sniffFile = $this->buildSniffFile($sniffName);
$sniffPath = getenv('LIB_PATH') . "/{$sniffFile}.php";
if (!file_exists($sniffPath) || !is_readable($sniffPath)) {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
throw new Exception("Non-existent of unreadable sniff file '{$sniffPath}' found.");
}

$standard = strtok($sniffName, '.');
$config = new Config();
$config->standards = [dirname(getenv('SNIFFS_PATH'))];
$config->sniffs = ["Inpsyde.{$sniffName}"];
$config->standards = [getenv('LIB_PATH') . "/{$standard}"];
$config->sniffs = [$sniffName];
$ruleset = new Ruleset($config);

$baseSniffNamespace = getenv('SNIFFS_NAMESPACE');
$sniffFqn = str_replace('/', '\\', $sniffFile);
foreach ($properties as $name => $value) {
$ruleset->setSniffProperty("{$baseSniffNamespace}\\{$sniffFqn}", $name, $value);
$ruleset->setSniffProperty(
$sniffFqn,
$name,
['scope' => 'sniff', 'value' => $value],
);
}

return new LocalFile($fixtureFile, $ruleset, $config);
}

private function buildSniffFile(string $sniffName): string
{
$parts = explode('.', $sniffName);
array_splice($parts, 1, 0, 'Sniffs');

return implode('/', $parts) . 'Sniff';
}
}
2 changes: 1 addition & 1 deletion tests/fixtures/Psr4Fixture.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php # -*- coding: utf-8 -*-
// @phpcsSniff CodeQuality.Psr4
// @phpcsSniff Inpsyde.CodeQuality.Psr4

namespace {

Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/argument-type-declaration.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.ArgumentTypeDeclaration
// @phpcsSniff Inpsyde.CodeQuality.ArgumentTypeDeclaration

use Psr\Container as PsrContainer;

Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/disable-call-user-func.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.DisableCallUserFunc
// @phpcsSniff Inpsyde.CodeQuality.DisableCallUserFunc

function test() {
// @phpcsErrorOnNextLine
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/disallow-magic-serialize.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

// @phpcsSniff CodeQuality.DisableMagicSerialize
// @phpcsSniff Inpsyde.CodeQuality.DisableMagicSerialize

class Foo {

Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/disallow-short-open-tag.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function (string $sniff, array $messages, array $warnings, array $errors, array
}
// @phpcsProcessFixtureEnd

// @phpcsSniff CodeQuality.DisallowShortOpenTag
// @phpcsSniff Inpsyde.CodeQuality.DisallowShortOpenTag
?>
<div>
<?= strtolower($x) ?>
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/element-name-minimal-length.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.ElementNameMinimalLength
// @phpcsSniff Inpsyde.CodeQuality.ElementNameMinimalLength

namespace {

Expand Down
3 changes: 1 addition & 2 deletions tests/fixtures/encoding-comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
namespace Inpsyde\CodingStandard\Tests\Fixtures;


// @phpcsSniff CodeQuality.EncodingComment
// @phpcsSniff Inpsyde.CodeQuality.EncodingComment

// @phpcsWarningCodeOnNextLine EncodingComment
// -*- coding: utf-8 -*-
Expand All @@ -15,4 +15,3 @@

<?php //-*- coding: utf-8 -*-
// @phpcsWarningOnPreviousLine CodeQuality.EncodingComment
?>
2 changes: 1 addition & 1 deletion tests/fixtures/forbidden-public-property.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.ForbiddenPublicProperty
// @phpcsSniff Inpsyde.CodeQuality.ForbiddenPublicProperty

$foo = 'foo';

Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/function-body-start.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.FunctionBodyStart
// @phpcsSniff Inpsyde.CodeQuality.FunctionBodyStart

namespace FunctionBodyStartTest;

Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/function-length-no-blank-lines.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.FunctionLength
// @phpcsSniff Inpsyde.CodeQuality.FunctionLength

// @phpcsSniffPropertiesStart
// $ignoreBlankLines = false;
Expand Down Expand Up @@ -339,4 +339,4 @@ function test_comments()
#8
#9
#10
}
}
4 changes: 2 additions & 2 deletions tests/fixtures/function-length-no-comments.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.FunctionLength
// @phpcsSniff Inpsyde.CodeQuality.FunctionLength

// @phpcsSniffPropertiesStart
// $ignoreComments = false;
Expand Down Expand Up @@ -197,4 +197,4 @@ function test_whitespaces() {



}
}
4 changes: 2 additions & 2 deletions tests/fixtures/function-length.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.FunctionLength
// @phpcsSniff Inpsyde.CodeQuality.FunctionLength

// @phpcsErrorOnNextLine
function test() {
Expand Down Expand Up @@ -597,4 +597,4 @@ function testCommentsWhitespaces() {
#9
#10
}
}
}
2 changes: 1 addition & 1 deletion tests/fixtures/hook-closure-return.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

// @phpcsSniff CodeQuality.HookClosureReturn
// @phpcsSniff Inpsyde.CodeQuality.HookClosureReturn

add_action('foo', 'bar');

Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/hook-priority.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

namespace Inpsyde\CodingStandard\Tests\Fixtures;

// @phpcsSniff CodeQuality.HookPriority
// @phpcsSniff Inpsyde.CodeQuality.HookPriority
add_action('foo', 'bar');

add_filter('foo', [ArrayObject::class, 'meh']);
Expand Down
3 changes: 1 addition & 2 deletions tests/fixtures/line-length.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.LineLength
// @phpcsSniff Inpsyde.CodeQuality.LineLength

?>
<!-- Warning two lines below: multiple attributes can go each in one line -->
Expand Down Expand Up @@ -117,4 +117,3 @@ function longComment() {
</div>
</div>
</div>

2 changes: 1 addition & 1 deletion tests/fixtures/nesting-level.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.NestingLevel
// @phpcsSniff Inpsyde.CodeQuality.NestingLevel

// @phpcsErrorOnNextLine
function a()
Expand Down
2 changes: 1 addition & 1 deletion tests/fixtures/no-accessors.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

// @phpcsSniff CodeQuality.NoAccessors
// @phpcsSniff Inpsyde.CodeQuality.NoAccessors

function getting() {

Expand Down
4 changes: 2 additions & 2 deletions tests/fixtures/no-else.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?php

// @phpcsSniff CodeQuality.NoElse
// @phpcsSniff Inpsyde.CodeQuality.NoElse

if ('x') {

Expand Down Expand Up @@ -36,4 +36,4 @@ public function test()
die();
}
}
}
}
2 changes: 1 addition & 1 deletion tests/fixtures/no-root-namespace-functions-multi.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?php
// @phpcsSniff CodeQuality.NoRootNamespaceFunctions
// @phpcsSniff Inpsyde.CodeQuality.NoRootNamespaceFunctions

namespace Foo {

Expand Down
Loading

0 comments on commit 29f8bc7

Please sign in to comment.